
On Fri, Feb 3, 2012 at 2:37 PM, AntC
Do people really write code with huge pile-ups of functions prefix upon prefix? Wouldn't that be confusing even when it's unidirectional?
Not really. Pipeline-like chains where you apply each function to the result of the previous one are quite common and readable, whether in the shell, Haskell, or your 'Yay!!' example. But possibly we aren't referring to the same thing.
I've seen some examples in other threads mixing dot notation with function composition with user-defined operators built with a dot (like >.< ) and a sprinkling of parentheses. They were indeed unreadable, but frankly, I don't think that was purely down to the dot notation.
Well, yeah. If you want to write confusing code you can certainly do that. You can do it already. I don't think adding another way to do it is a huge problem. I think you can expect people to not shoot themselves in the feet intentionally. What -is- a problem is if you are forced or encouraged to write confusing code (because there's no other way to do it or because it's the path of least resistance), which is why I dislike proposals which make postfix application mandatory for some purposes, or which make it have different behaviour from normal prefix application.
And now that I've found it, I so love:
customer.lastName.tail.head.toUpper -- Yay!
I agree that this is nice, but it only works with single-argument functions.
I notice that for prefix functions you do sometimes need a bit of trickery to deal with partial application and inconvenient order of parameters. Of course there's parentheses to help, but there's also a family of combinators, especially: ($) -- loose-binding function application (.) -- function composition
So I'm going to take your post as a challenge: can we build a family of combinators for postfix style? The objective is to 'keep up the momentum' left to right.
I've already been using one such: (.$) = flip ($) -- looks combinator-ish to me! (.$!) = flip ($!) -- strict version
customer.lastName .$ tail .$ head .$ toUpper -- Yay.$!
I don't see a benefit here over plain dot...
For example, take the filter function from the Prelude:
filter :: (a -> Bool) -> [a] -> [a]
But for postfix function application, this latter order is the one you want:
[1..10].filter even is a lot more intuitive than even.filter [1..10]
Agreed. Easy. How do you like these?:
[1..10] .$ filter even [1..10] .$ filter even .$ sum ^ 2 [1..10] .$ filter even .$ foldr (+) 0 ^ 2
I'm looking at those thinking 'Oh yes! foldr (+) 0 is atomic-ish'.
Oh, well, this looks alright. Hmm.
If we restrict this postfix notation to only selecting fields from records,
Would you like to include 'virtual' fields like fullName or area? Or fst or last or middleInitial?
I guess these would be OK. Virtual fields are effectively required to be single-argument, so you don't encounter the argument-order problem, and if you can write them equally prefix and postfix then you can avoid the mix-and-match problem. But this opinion might be obsolete, see below.
So my preferred solution is:
- Selecting fields from records can be written (equivalently) using either prefix or postfix notation; - Everything else can be written only with prefix notation.
My second-choice solution is to not introduce postfix notation.
Noted. (And from the above, you won't expect me to agree.) I guess GHC HQ gets the final decision. Glad I'm not having to mediate.
If postfix code can be conveniently written using your (.$) combinator (and presumably its extended family), with no changes required to existing or future functions, I guess it could all work out. What I'm afraid of is that introducing postfix notation results in a pressure to make functions convenient to use with it, and then we eventually end up in the morass I described. If we can reasonably expect that having the postfix combinators around will remove that pressure or that people will resist it, and that we won't end up with a proliferation of writeIORef-endian functions on Hackage, I guess I would be okay with it. I'm not sure what we would need to be able to reasonably expect that. (Not that me being okay with it is required for anything.)