Why is <$> left associative?

fmap also <$> because it is a functional application ( $ ) in the functor category.

 (+5) $ (*10) $ 10 -- 105 (+5) <$> (*10) <$> [1,2,3] -- [15,25,35] 

Then I thought that in this case <*> is a functional application in the category of applicative functor, and this should work:

 [(+5), (+10)] <*> [(*10), (*100)] <*> [1,2,3] -- ERROR -- however: [(+5), (+10)] <*> ([(*10), (*100)] <*> [1,2,3]) -- [15,25,35,...] 

So, <$> only works because fmap for functions turns out to be a postcomposition, therefore (+5) <$> (*10) becomes (+5) . (*10) (+5) . (*10) , which then applies to [1,2,3] .

However, left associativity for all application operators ( <<= enabled) seems to me a poor design choice, especially after they recognized the similarities with $ , which is already right-associative. Is there another reason for this?

+7
source share
1 answer

Indeed, the reason, perhaps, is that it allows <$> and <*> to share one priority level. We definitely want <*> remain associative, so things like

 Prelude> foldr <$> [(+),(*)] <*> [0,1] <*> [[1,2,3], [4,5,6]] [6,15,7,16,0,0,6,120] 

works, and it also makes the <$> behavior correct, even if it does not have a higher priority. Actually a chain of several <$> operators is really not very useful with left associativity.

However, this is also not very useful with legal associativity. As Chapner commented, it's actually a little funny that $ is right-associative. Of course, this allows you to write compositions like

 Prelude> sum $ map (+3) $ take 19 $ cycle [4..7] 160 

but then it could also be written as elegant as possible

 Prelude> sum . map (+3) . take 19 . cycle $ [4..7] 160 

(more elegant, I say, because here the computational chain is analyzed as a single functional pipeline, and not the imperative style of "do this, then this, then ..."). Thanks to the laws of the functor, this can be done in the same way as <$> and . as with $ and . .

The only reason you might prefer the multiple- $ style is because it allows infix expressions in the pipeline, perhaps the most common example is updating lenses (which are usually written with inverted & , 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 a very low priority, much lower than any infix operator. This does not apply to <$> , so you cannot 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 this case, you still need to use some parentheses, and then you can also do this using the low-priority 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 parsers around each update:

 Prelude Control.Lens> (ix 1+~9) . (ix 2*~8) <$> [[4..8], [5..9]] [[4,14,48,7,8],[5,15,56,8,9]] 
+7
source

All Articles