Working through the Haskell Book and my brain is breaking on the following example. I really don't know what the flip
function is doing on line 21
1 class Functor f where
2 fmap :: (a -> b) -> f a -> f b
3
4 class Functor f => Applicative f where
5 pure :: a -> f a
6 (<*>) :: f (a -> b) -> f a -> f b
7
8 class Applicative f => Monad f where
9 return :: a -> f a
10 (>>=) :: f a -> (a -> f b) -> f b
11
12 instance Functor ((->) r) where
13 fmap = (.)
14
15 instance Applicative ((->) r) where
16 pure = const
17 f <*> a = \r -> f r (a r)
18
19 instance Monad ((->) r ) where
20 return = pure
21 ra >>= arb = flip arb <*> ra
-- flip :: (a -> b -> c) -> b -> a -> c
-- ra >>= arb = flip arb <*> ra
As I understand it, flip takes a function that takes two arguments, then two individual arguments, and returns a value. In the bind example, are we passing arb
as the (a -> b -> c)
, then <*>
as the b
in flip's signature, and finally ra
as the a
? I can't see it.
I've tried making the types more specific to my actual example so you could rewrite <*>
as
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
and I can do the same for bind
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
so even a dummy like myself can see that if we could swap <*>
around we could line then up like
(<???>) :: (r -> a) -> (r -> a -> b) -> (r -> b)
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
but looking at the second arguments there, the first one wants an r
as its first argument and bind wants an a
So somehow flip
is the book's example is doing that for us, but I really don't understand how. Any help would be greatly appreciated.
Thank you!
Top-level point of confusion, I think: flip
is modifying arb
, not modifying <*>
as you seem to believe. We have "modified" <*>
to have the "right" argument order just by giving <*>
its arguments in the opposite order we got them!
Now for the details. We have, as you noted:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
So, since we have on the left hand side written
ra >>= arb = ...
then what we have in scope is:
ra :: r -> a
arb :: a -> r -> b
(Note how the names were chosen to reflect the types!) Rewriting the type you gave for flip
, we have
flip :: (a -> b -> c) -> b -> a -> c -- original
flip :: (a -> r -> b) -> r -> a -> b -- rename variables
hence:
flip arb :: r -> a -> b
Now recall the type of (<*>)
that you wrote:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
So for the first argument to (<*>)
, we want something of type r -> a -> b
. Hey! flip arb
has that type! For the second argument, we want something of type r -> a
. And we're in luck again, because ra
has that type, so...
flip arb <*> ra :: r -> b
(As usual with infix operators, this is the application of the operator (<*>)
the arguments flip arb
and ra
.) What type were we hoping to have? Well, we go back to the type of (>>=)
now:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
After taking two arguments, this is supposed to return something of type r -> b
. Cool, that's what we have built.
ra >>= arb = flip arb <*> ra
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.