Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Applicative Functor Example

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?

like image 817
clay Avatar asked May 29 '14 01:05

clay


People also ask

Is applicative a functor?

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.

Is Fmap a functor?

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.

What are functor laws?

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.

Is monad a functor?

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.


1 Answers

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


A more symbolic appraoch

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
like image 71
Davorak Avatar answered Oct 15 '22 00:10

Davorak