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

Deriving monad bind from applicative (<*>) confusion

阅读 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 接受一个函数,该函数接受两个参数,然后是两个单独的参数,returns 一个值。在绑定示例中,我们是否将 arb 作为 (a -> b -> c) 传递,然后将 <*> 作为 flip 签名中的 b 传递,最后将 ra 作为 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)

但是看看那里的第二个参数,第一个想要一个 r 作为它的第一个参数,而 bind 想要一个 a

不知何故 flip 这本书的例子正在为我们做这件事,但我真的不明白怎么做。任何帮助将不胜感激。

谢谢!

顶级混淆点,我认为:flip是在修改arb,而不是像你认为的那样修改<*>。我们有 "modified" <*> 来获得 "right" 参数顺序,只需按照我们得到的相反顺序给 <*> 它的参数!

现在详细介绍。如您所述,我们有:

(>>=) :: (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

(与中缀运算符一样,这​​是运算符 (<*>) 参数 flip arbra 的应用。)我们希望拥有什么类型?好吧,我们现在回到 (>>=) 的类型:

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

接受两个参数后,这应该是 return 类型 r -> b 的东西。太棒了,这就是我们建造的。

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