从应用 (<*>) 混淆派生 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 arb
和 ra
的应用。)我们希望拥有什么类型?好吧,我们现在回到 (>>=)
的类型:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
接受两个参数后,这应该是 return 类型 r -> b
的东西。太棒了,这就是我们建造的。
ra >>= arb = flip arb <*> ra
阅读 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 arb
和 ra
的应用。)我们希望拥有什么类型?好吧,我们现在回到 (>>=)
的类型:
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
接受两个参数后,这应该是 return 类型 r -> b
的东西。太棒了,这就是我们建造的。
ra >>= arb = flip arb <*> ra