简体   繁体   中英

Why fmap f xs = pure f <*> xs?

class Functor f => Applicative f where
       pure :: a -> f a
       (<*>) :: f (a -> b) -> f a -> f b

"pure" plays two roles:
* The degenerate case when you have a 0-ary function, kind of.
* fmap f xs = pure f <*> xs

I don't understand why

fmap f xs = pure f <*> xs

I mean pure should take any a and return fa . But what does pure f do? Even pure (f <*> xs) makes sense to me.

Maybe a concrete example would be illustrative. Take the list applicative. <*> applies each function from its left operand to each value from its right:

fs <*> xs = [f x | f <- fs, x <- xs]

And pure wraps a value in a singleton list:

pure (+ 1) = [(+ 1)]

So pure f <*> xs = fmap f xs , because <*> applies each function— of which there happens to be only one —to each value, while fmap applies one function to each value:

pure (+ 1) <*> [1, 2, 3]
=
[(+ 1)] <*> [1, 2, 3]
=
[f x | f <- [(+ 1)], x <- [1, 2, 3]]
=
[(+ 1) x | x <- 1, 2, 3]
=
[x + 1 | x <- 1, 2, 3]
=
[2, 3, 4]


fmap (+ 1) [1, 2, 3]
=
[(+ 1) x | x <- [1, 2, 3]]
=
[x + 1 | x <- [1, 2, 3]]
=
[2, 3, 4]

This is also how the <$> and <*> operators work together to apply a multi-argument function over the results of multiple actions, eg:

(*) <$> [1..5] <*> [1..5]
=
((*) <$> [1..5]) <*> [1..5]
=
[(1 *), (2 *), (3 *), (4 *), (5 *)] <*> [1..5]
=
[ (1 *) 1, (2 *) 1, (3 *) 1, (4 *) 1, (5 *) 1
, (1 *) 2, (2 *) 2, (3 *) 2, (4 *) 2, (5 *) 2
, (1 *) 3, (2 *) 3, (3 *) 3, (4 *) 3, (5 *) 3
, (1 *) 4, (2 *) 4, (3 *) 4, (4 *) 4, (5 *) 4
, (1 *) 5, (2 *) 5, (3 *) 5, (4 *) 5, (5 *) 5
]
=
[ 1,  2,  3,  4,  5
, 2,  4,  6,  8, 10
, 3,  6,  9, 12, 15
, 4,  8, 12, 16, 20
, 5, 10, 15, 20, 25
]

This could also have been written pure (*) <*> [1..5] <*> [1..5] .

<$> builds an action (in this case a list) returning (containing) partially applied functions, and <*> takes those functions and applies them to arguments. (And if the function takes more than two arguments, then this may also result in partially applied functions, which can be applied to more arguments with another application of <*> .)

The same laws hold in other “container-like” applicatives such as Maybe or Either e (for some e ), as well as “action-like” applicatives such as IO , Cont r , or Async .

But what does pure f do?

Given, f :: a -> b , we obtain pure f :: f (a -> b) the last f being any applicative functor. This creates a value of the right type to pass as the first argument to

(<*>) :: f (a -> b) -> f a -> f b

I mean pure should take any a and return fa

Exactly -- in this case the a you mention is the function type a -> b I mentioned above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM