从应用(<*>)混淆派生monad绑定

时间:2019-01-22 17:57:53

标签: haskell monads reader

在研究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就是本书的例子为我们做的事情,但是我真的不明白如何做。任何帮助将不胜感激。

谢谢!

1 个答案:

答案 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 arbra的应用。)我们希望拥有哪种类型?好了,我们现在回到(>>=)的类型:

(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)

在接受两个参数之后,应该返回类型r -> b的东西。酷,这就是我们所建立的。

ra >>= arb = flip arb <*> ra