在研究Haskell书时,我的脑子在下面的示例中不知所措。我真的不知道第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
据我了解,flip接受一个函数,该函数接受两个参数,然后是两个单独的参数,并返回一个值。在绑定示例中,我们将arb
传递为(a -> b -> c)
,然后将<*>
传递为flip签名中的b
,最后将ra
传递为{{1 }}?我看不到。
我尝试使类型更适合实际示例,以便您可以将a
重写为
<*>
对于绑定我也可以做
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
因此,即使像我这样的假人也可以看到,如果我们可以交换(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
我们可以像
<*>
但是查看那里的第二个参数,第一个参数想要一个(<???>) :: (r -> a) -> (r -> a -> b) -> (r -> b)
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
作为其第一个参数,而bind想要一个r
以某种方式a
就是本书的例子为我们做的事情,但是我真的不明白如何做。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:3)
我认为顶级的混乱点是:flip
正在修改arb
,而不是您似乎认为的那样修改<*>
。我们已经对<*>
进行了“修改”,以使<*>
的论据以与获得它们相反的顺序具有正确的论据顺序!
详细信息。如您所述,我们有:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
所以,因为我们在左侧写了
ra >>= arb = ...
那么我们的范围是:
ra :: r -> a
arb :: a -> r -> b
(请注意,如何选择名称以反映类型!)重写您为flip
指定的类型,
flip :: (a -> b -> c) -> b -> a -> c -- original
flip :: (a -> r -> b) -> r -> a -> b -- rename variables
因此:
flip arb :: r -> a -> b
现在回想一下您编写的(<*>)
的类型:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
因此对于(<*>)
的第一个参数,我们需要类型r -> a -> b
的东西。嘿! flip arb
就是这种类型!对于第二个参数,我们需要类型r -> a
的东西。而且我们很幸运,因为ra
具有这种类型,所以...
flip arb <*> ra :: r -> b
(与infix运算符一样,这是运算符(<*>)
和参数flip arb
和ra
的应用。)我们希望拥有哪种类型?好了,我们现在回到(>>=)
的类型:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
在接受两个参数之后,应该返回类型r -> b
的东西。酷,这就是我们所建立的。
ra >>= arb = flip arb <*> ra