Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Well I believe that no pipe is better than a a handicapped pipe operator.

The Elixir implementation inverts the classical order of piping last in functional languages to the detriment of it. IMO a language should either support pipe last AND currying by default or supply a multitude of thread operators like Clojure does (->, ->>, as->, etc). Elixir's is just middle-of-the-road-weird.



Is it to its detriment? What's really at stake here? Elixir's pipe operator takes a stance, and I love that. It enforces consistency. I feel it's a lot better than having the "sometimes first, sometimes last" that Erlang and Clojure have.


IME it is. Many Elixir apis end up forcing an unnatural parameter order just so that the entire body can be piped through.

Clojure is way more consistent in this regard:

  - thread first (->) when operating on maps.
  - thread last (->>) when operating on sequences.
  - as-> "choose your own adventure".


Huh? Almost always the parameter order is "the type of the module first" (except builders bla bla). This is super easy to remember, and this convention also encourages good code organization and module naming.

The only place where pipe order bristles is Enum.reduce, but I'd bet if I counted I'd have wanted it the normal way more often than the backwards way.


I just gave reduce as an example in my response without reading yours first. Can you explain why it would be more desirable to have it last in reduce? I have never felt this pain though, again, don't come from a functional background.


The easiest way to say it is:

often you want to apply a list of actions to an object.

This is a "backward reduce".

I don't feel it often, but when I do, it's such a bummer.


I don't have a functional background so I can only empathize that only being allowed to pipe first is not what folks are used to. I am having trouble understanding your argument, however, that includes both "consistent" and "choose your own adventure". I also don't buy that, other than simply being used to it, that piping last to sequences is more "natural". "reduce a into b with c" or "reduce value a into value b using function c" reads perfectly natural to me. I'm happy to hear arguments otherwise.


You’re missing the crux of the argument: auto-currying. In languages like Elm and Ocaml all functions are single arity which means a multi-arity function is just a partially-applied single arity function thus you can treat all functions as being single arity. This also means the pipe operator can be implemented as a higher order function being, as such, first class. Languages without auto-currying have to resort to macros.

Clojure also doesn’t have auto currrying, but makes up for it by giving you 6 variants and creating a consistent default library for sequences and associative structures.

So, the pipe first operator is just a dirty hack.


I'm familiar with auto-currying from Haskell I've never worked seriously in a language that has it. But yes, that makes sense! I never thought about that.

I'm a bit stuck on your Clojure example still, though. If a language doesn't have auto-currying (or even currying at all in Elixir's case), why does the argument order matter? Whether it's a List or a Map, what does it matter if it's passed first instead of last?


There is no general implicit currying. I suppose if we are exact with CS terminology, currying means converting to 1-argument functions, so that's out.

But the threading macros do partial application in that they put the threaded-through value as an implicit argument. Look at the first examples in https://clojure.org/guides/threading_macros - the -> (thread-first) macro needs functions like assoc and update to take the map as the first argument.

And of course explicit use of partial application is also pretty common and argument order matters similarly there, just like it would eg in Python.


I was more after an example of why argument order matters in currying collection functions, but I actually get it now :) With the object as the last parameter, you are able to create a function that, say, always reduces to a list with a specific function and takes an object. So yes, I understand peoples' objections now.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: