Hacker News new | ask | show | jobs
by klibertp 1862 days ago
I was very, very disappointed that the `tap` macro has nothing to do with pattern_tap: https://github.com/mgwidmann/elixir-pattern_tap

Basically, in Elixir pipelines are not very friendly to simple destructuring: if a call at the beginning of the pipeline returns a tuple of `{:ok, result}`, you can't use either of shortcut syntaxes for lambdas (&Mod.fun/arity and &Mod.fun(&1)), you have to use `fn` and destructure in its head. pattern_tap solves this quite elegantly, but I was told that it's a "non-standard macro that people don't know, so it shouldn't be used"... So when I saw `tap` in Kernel, I though that maybe it's similar at least... unfortunately, it's not similar at all, and now the global identifier `tap` is taken, which made the situation even worse :(

1 comments

> if a call at the beginning of the pipeline returns a tuple of `{:ok, result}`

In my understanding, pipeline are mostly reserved for “unfailable” operations operating on raw data; whereas the where/else/do macro is more oriented towards errors handling; would it work better in your case?

I think you mean `with`, not `where`? Yes, it helps a bit in some cases, but it's not a replacement for a pipeline - mainly because you'd need to name your intermediate results and "thread" them through the calls yourself.

I think I gave a bad example, the better one would be a function returning datetime in the format of :erlang.localtime: `{{Year,Month,Day},{Hour,Min,Sec}}`. I would like to be able to use this value in a pipeline, by passing only a `{Hour, Min}` tuple to the next call in the pipeline.

With pattern_tap it looks like this:

    :erlang.localtime()
    |> tap({_, {H,M,_}} ~> {H, M})
    |> do_something
Without - there are at least 3-4 ways of doing this, each with pros and cons, but all of them are more verbose than pattern_tap. If you want a single value only, there's `elem`, but if you need a few - you're out of luck. `destructure` only works on lists, and `match?` only return a boolean, not whatever was matched.

`then` macro makes it a bit better, but you still need to create a lambda with the longhand syntax, which is exactly what I wanted to avoid, so it's hardly a solution, even though it may be the best way to do this for now...

EDIT: this is in contrast to Clojure, where maps and vectors are callable, and you get `juxt` in the stdlib. So it's not like pipelines in general can't support convenient extraction of subsets of data flowing through the pipe, it's just that Elixir decided not to support this.

Hm, this works and is about as terse as `pattern_tap`:

    :erlang.localtime()
    |> case do; {_, {h,m,_}} -> {h, m}; end
    |> do_something
Not that I'd want to do that in production code, but I felt a bit nerd-sniped here, to see the shortest way I could find without dependencies.
That's actually what pattern_tap's tap macro expands into :) See: https://github.com/mgwidmann/elixir-pattern_tap/blob/master/...
> I think you mean `with`, not `where`?

Indeed, my bad.

> the better one would be a function returning datetime in the format of :erlang.localtime: `{{Year,Month,Day},{Hour,Min,Sec}}`

I see what you mean. Yeah, I agree with the rest.