I'm reading the Learn You a Haskell book. I'm struggling to understand this applicative functor code:
(*) <$> (+3) <*> (*2) $ 2
This boils down to: (3+2) * (2*2) = 20
I don't follow how. I can expand the above into the less elegant but more explicit for newbie comprehension version:
((fmap (*) (+3)) <*> (*2)) 2
I understand the basics of the <*>
operator. This makes perfect sense:
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
But I don't see how the command works? Any tips?
Applicative functors are the programming equivalent of lax monoidal functors with tensorial strength in category theory. Applicative functors were introduced in 2008 by Conor McBride and Ross Paterson in their paper Applicative programming with effects.
The expression fmap (*2) is a function that takes a functor f over numbers and returns a functor over numbers. That functor can be a list, a Maybe , an Either String, whatever. The expression fmap (replicate 3) will take a functor over any type and return a functor over a list of elements of that type.
Functor Laws If two sequential mapping operations are performed one after the other using two functions, the result should be the same as a single mapping operation with one function that is equivalent to applying the first function to the result of the second.
A functor is a data type that implements the Functor typeclass. An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.
One method to approach this types of questions is to use substitution. Take the operator, in this case (<*>)
or function, get its implementation and insert it to the code in question.
In the case of (*) <$> (+3) <*> (*2) $ 2
you are using the ((->) a)
instance of Applicative
found in the Applicative
module in base, you can find the instance by clicking the source link on the right and searching for "(->":
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
Using the definition for (<*>)
we can continue substituting:
((fmap (*) (+3)) <*> (*2)) 2 == (fmap (*) (+3)) 2 ((*2) 2)
== (fmap (*) (+3)) 2 4
Ok now we need the Functor instance for ((->) a)
. You can find this by going to the haddock info for Functor
, here clicking on the source link on the right and searching for "(->" to find:
instance Functor ((->) r) where
fmap = (.)
Now continuing substituting:
(fmap (*) (+3)) 2 4 == ((*) . (+3)) 2 4
== (*) ((+3) 2) 4
== (*) 5 4
== 20
Many people report better long term sucess with these types of problems when thinking about them symbolically. Instead of feeding the 2 value through the problem lets focus instead on (*) <$> (+3) <*> (*2)
and only apply the 2 at the end.
(*) <$> (+3) <*> (*2)
== ((*) . (+3)) <*> (*2)
== (\x -> ((*) . (+3)) x ((*2) x))
== (\x -> ((*) . (+3)) x (x * 2))
== (\x -> (*) (x + 3) (x * 2))
== (\x -> (x + 3) * (x * 2))
== (\x -> 2 * x * x + 6 * x)
Ok now plug in 2 for x
2 * 2 * 2 + 6 * 2
8 + 12
20
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With