5 ms·
I love the pipe operator in Elixir!
by leishman 4y ago
I love the pipe operator in Elixir!
- dmix 4y agoThe current JS one isn't as nice as the Elixir one, at least it wasn't when I tried using it via Babel a couple yrs ago.
- ollien 4y agoThe JS one does seem to have some more power than the Elixir one. For instance, in Elixir, if it's a bit kludgy to pipe to a second or third argument. I find this often when I want to insert into a map. You can always define more functions, but otherwise it's annoying, because you end up with something like computation() |> &(Map.put(my_map, key, &1)).() That said, with this less-power, you do kind of end up forced to design your functions in a way to where piping makes sense, and IMO it leads to cleaner and more consistent APIs.
- ch4s3 4y agoFrom what I understand the constraint is intentional to guide you in the direction of writing simple pipe chains.
- dmix 4y agoThat's probably a wise choice. Pipes are great for simple situations, mostly for code clarity. But it can be abused easily, like a hammer seeking nails. It's similar to await/async, you eventually start designing code that better suits that interface rather than pigeonholing it with complex syntax.
- spapas82 4y agoClojure has thread first ->, thread last -> and even thread as as->, to define where the pipe will be applied. I find it very cool!
- tytho 4y agoThere is another way that isn't _as_ kludgy, but still not as nice as the JavaScript proposal: computation() |> then(&Map.put(my_map, key, &1)) It's the big reason the `then/2` function was created from my understanding.
- lvass 4y agoIt's nice in Elixir because there's a strong convention that the first argument is where you'd almost always pipe into. The JS proposal is better for retrofitting in a language.
- ollien 4y agoOh wow, TIL about `Kernel.then/2`. That definitely works around the syntax problem. An aside, the implementation is kind of amusing. It almost seems unnecessary for this to be a macro but maybe the compiler can optimize this a bit more? I would expect TCO to simplify of my "simple" implementation of def then(value, fun) do fun.(value) end https://github.com/elixir-lang/elixir/blob/a64d42f5d3cb6c32752af9d3312897e8cd5bb7ec/lib/elixir/lib/kernel.ex#L2511 https://github.com/elixir-lang/elixir/blob/a64d42f5d3cb6c327...
- WastingMyTime89 4y agoPipes work really well with named arguments and partial-application. Both functionalities make it easy to get the unary function you want with minimal cruft. Lambdas solve the more complex case. In Ocaml, you often end up doing things like: List.create 0 3 |> List.map ~f:(fun x -> x+1) |> List.fold ~init:0 ~f:(fun acc x -> x+acc) |> Stdio.print_endline "%d" I'm ambivalent about adding them to JS however. It's a nice feature but I don't think it works well with the rest of the syntax.
- sph 4y agoAs I mentioned upthread, most Elixir functions are designed to have the thing they operate on as first argument. computation() |> &(Map.put(my_map, key, &1)) is terrible style when Map.put(my_map, key, computation()) works just as well and is more readable. It is pretty rare to have a pipeline that needs to insert the value elsewhere than the first position. And please, do not write single element pipelines, I see them far too often from Elixir beginners.
- ollien 4y agoI agree! I even pointed this out in my comment, but perhaps not clearly :) I think that the way it's done is a net-positive in designing cleaner APIs, but there are times when I've already done a pipeline, and storing the output is just the last step. This last step is just frustratingly, not always possible. I don't think one should do something like the above, it's just what you must resort to if you _did_ want to do it.
- sph 4y agoThere is nothing wrong with doing data = this |> is |> a |> pipeline save_to_file(file, data) Instead of trying to put the call to save_to_file into the pipeline by wrapping it in a closure.
- delta_p_delta_x 4y agoI love the pipe operator in OCaml! I wrote this line for a compilers class: let _ = apply_effects effs in () in m |> fetch |> decode_execute |> memory_writeback Actually looks like a RISC pipeline! It looks even better with code ligatures[1]. [1]: https://i.imgur.com/Qwx8CDr.png https://i.imgur.com/Qwx8CDr.png
- sph 4y agoThe pipe operator in Elixir also benefits from having the subject of most functions in the standard library as first argument. No need for the % hack operator, so you can just do: "hello world" |> String.split(" ", trim: true) |> Enum.map(&String.upcase/1)
- vorotato 4y agoThis isn't the pipe operator in elixir. It's from some php derivative language that facebook uses and you shouldn't trust it, because nobody could even show in TC39 that it was sound.