Proposal: make the $ operator left-associative
Arguments in favour
- $ was introduced as a combinator for function application. Therefore we might expect that whenever we have a function application we can stick a $ in there. But this is not the case. Consider the following expression:
f x y
There are two applications here and if $ behaved like function application we would be able to write:
f $ x $ y
But as it is now this expression means something completely different.
(these following points taken from Dan Doel's post on the haskell-prime mailing list)
- Anything of the form:
f $ g $ h $ x
with right associative ($) can instead be written:
f . g . h $ x
where the associativity of ($) doesn't matter. It's not uncommon to want to peel off the end of such a pipeline to eliminate a point. For the second form, such a translation is:
\x -> f . g . h $ x ==> f . g . h
However:
\x -> f $ g $ h $ x ==> f $ g $ h
Is invalid, so one might argue that writing such pipelines with composition is a better habit to get into, as it allows easier cleanup of code in this way (if you like somewhat point-free code, that is).
- Left associative () allows you to eliminate more parentheses. Per #1, any parentheses eliminated by right associative () can be eliminated by (.) and a single (). However, left associative () allows, for instance:
f (g x) (h y) ==> f $ g x $ h y
- Left associative () is consistent with left associative (!). The right associative version of the latter is inconvenient, because it only allows things to be (easily) strictly applied to the last argument of a function. Needing to strictly apply to other arguments gives rise to things like:
(f $! x) y z
((f $! x) $! y) $! z
Left associative, these are:
f $! x $ y $ z
f $! x $! y $! z
There may be more arguments, but those are the ones I've heard that I can think of at the moment. #3 strikes me as the most likely to bite people (the other two are more stylistic issues), but I suppose I don't know the relative frequency of strict pipelines (f $! g $! x) versus strict applications at non-final arguments.
Arguments against
- This would break a lot of code.