一些脚注李的回答 https://stackoverflow.com/a/40132248/2751851:
但是,那bind
函数看起来很奇怪。为什么是f
and g
反过来嵌套?
Because bind
是向后的。比较(>>=)
及其翻转版本(=<<)
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(=<<) :: Monad m => (a -> m b) -> m a -> m b
或者,在您的具体示例中:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
而在实践中我们倾向于使用(>>=)
经常多于(=<<)
(因为如何(>>=)
从语法上来说,从理论的角度来看,它非常适合通常用来构建的管道单子)(=<<)
是最自然的书写方式。特别是,与fmap
/(<$>)
and (<*>)
更加明显:
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(=<<) :: Monad f => (a -> f b) -> f a -> f b
当我申请时apply
/bind
对于一元和二元函数,它们产生相同的结果。这没有多大意义。
这是关于函数实例的一个偶然事实。让我们将专门的签名并排放置:
(<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
Monad
超越Applicative
通过提供根据先前的效果确定下一个效果的方法results(与“之前的效果”相反——Applicative
已经可以做到了)。在这种情况下,效果由一个函数组成,该函数根据给定类型的参数生成值r
。现在,由于具有多个参数的函数(即返回函数的函数)可以翻转,因此两者之间没有显着差异(r -> (a -> b))
and (a -> (r -> b))
(flip
可以轻松地将一种改变为另一种),这使得Monad
实例为(->) r
完全等价于Applicative
one.