[英]Deriving monad bind from applicative (<*>) confusion
Working through the Haskell Book and my brain is breaking on the following example. 通过Haskell Book和我的大脑正在打破下面的例子。 I really don't know what the
flip
function is doing on line 21 我真的不知道第21行的
flip
功能是做什么的
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. 据我了解,flip接受一个函数,它接受两个参数,然后是两个单独的参数,并返回一个值。 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
? 在绑定示例中,我们将
arb
作为(a -> b -> c)
传递,然后将<*>
作为b
的翻转签名,最后ra
作为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
但是看那里的第二个参数,第一个想要一个
r
作为它的第一个参数,而bind想要一个a
So somehow flip
is the book's example is doing that for us, but I really don't understand how. 所以不知何故
flip
是本书的例子是为我们做的,但我真的不明白如何。 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. 我认为顶级的混淆点是:
flip
正在修改arb
,而不是修改<*>
因为你似乎相信。 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
的类型,我们有
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
. 因此,对于
(<*>)
的第一个参数,我们需要类型为r -> a -> b
。 Hey! 嘿!
flip arb
has that type! flip arb
有那种类型! For the second argument, we want something of type r -> a
. 对于第二个参数,我们需要
r -> a
类型的东西。 And we're in luck again, because ra
has that type, so... 我们再次幸运,因为
ra
有这种类型,所以......
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? (和中缀运算符一样,这是运算符
(<*>)
的应用,参数flip arb
和ra
。)我们希望有什么类型的? 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
. 在取两个参数之后,这应该返回
r -> b
类型的东西。 Cool, that's what we have built. 很酷,这就是我们建立的。
ra >>= arb = flip arb <*> ra
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.