Really, the reason is probably just that it allows <$>
and <*>
to share one precedence level. We definitely want <*>
to be left-associative so stuff like
Prelude> foldr <$> [(+),(*)] <*> [0,1] <*> [[1,2,3], [4,5,6]]
[6,15,7,16,0,0,6,120]
works, and this also makes <$>
behave the correct way even though it doesn't have higher precedence. Actually chaining multiple <$>
operators is indeed not very useful with left-associativity.
However, it would also not be very useful with right-associativity. As chepner commented, it's actually a bit funny that $
is right-associative. Sure, that allows writing compositions like
Prelude> sum $ map (+3) $ take 19 $ cycle [4..7]
160
but then, this could just as well be written as the arguably more elegant
Prelude> sum . map (+3) . take 19 . cycle $ [4..7]
160
(more elegant I say, because here the computation-chain is parsed as a single functional pipeline, rather than imperative-style “do this, then that, then...”). Thanks to the functor laws, this can be done just the same way with <$>
and .
as with $
and .
.
The only reason why you might prefer the multiple-$
style is that it allows infix expressions in the pipeline, perhaps the most common example being lens updates (which are typically written with the flipped &
, but the principle is the same):
Prelude Control.Lens> [4..7] & ix 1+~9 & ix 2*~8
[4,14,48,7]
This works because $
and &
have very low precedence, pretty much lower than any infix operator. That's not the case for <$>
so you can't do
Prelude Control.Lens> ix 1+~9 <$> [[4..8], [5..9]]
<interactive>:23:1: error:
Precedence parsing error
cannot mix ‘+~’ [infixr 4] and ‘<$>’ [infixl 4] in the same infix expression
In such a case, you need to use some parentheses anyway, and then you might as well do it with the also low-precedence composition operators from Control.Category
:
Prelude Control.Lens Control.Category> (ix 1+~9 >>> ix 2*~8) <$> [[4..8], [5..9]]
[[4,14,48,7,8],[5,15,56,8,9]]
or with parens around each updater:
Prelude Control.Lens> (ix 1+~9) . (ix 2*~8) <$> [[4..8], [5..9]]
[[4,14,48,7,8],[5,15,56,8,9]]
$
right-associative? – Apiaristfmap
is better thought of as function lifting rather than function application. Oncefmap
returns the lifted function, it is applied the same as any other function; no special application required. – Apiarist