haskell - 关于 >>= Monad 运算符的签名

标签 haskell monads

这是 Haskell 中众所周知的 >>= 运算符的签名

>>= :: Monad m => m a -> (a -> m b) -> m b

问题是为什么函数的类型是
(a -> m b)

代替
(a -> b)

我想说后一个更实用,因为它允许在定义的 monad 中直接集成现有的“纯”函数。

相反,写一个通用的“适配器”似乎并不难
adapt :: (Monad m) => (a -> b) -> (a -> m b)

但无论如何,我认为您已经拥有 (a -> b) 的可能性更大。而不是 (a -> m b) .

笔记。 我解释了我所说的“实际”和“可能”是什么意思。
如果您还没有在程序中定义任何 monad,那么,您拥有的函数是“纯”(a -> b)您将拥有 (a -> m b) 类型的 0 个函数只是因为你还没有定义m .如果你决定定义一个 monad m它需要有新的a -> m b定义的功能。

最佳答案

原因是(>>=)更一般。您建议的功能称为 liftM 并且可以很容易地定义为

liftM :: (Monad m) => (a -> b) -> (m a -> m b)
liftM f k  =  k >>= return . f

这个概念有自己的类型类,称为 Functorfmap :: (Functor m) => (a -> b) -> (m a -> m b) .每Monad也是 Functorfmap = liftM ,但由于历史原因,这不是( yet )在类型类层次结构中捕获。

adapt你建议可以定义为
adapt :: (Monad m) => (a -> b) -> (a -> m b)
adapt f = return . f

请注意,有 adapt相当于拥有 returnreturn可以定义为adapt id .

所以任何有 >>=也可以同时具备这两个功能,但反之则不行。 There are structures that are Functors but not Monads .

这种差异背后的直觉很简单:monad 中的计算可以依赖于先前 monad 的结果。重要的是(a -> m b)这意味着不仅仅是b ,也是它的“效果”m b可以依赖 a .例如,我们可以有
import Control.Monad

mIfThenElse :: (Monad m) => m Bool -> m a -> m a -> m a
mIfThenElse p t f = p >>= \x -> if x then t else f

但是不能只用 Functor m 来定义这个函数约束,仅使用 fmap .仿函数只允许我们改变“内部”的值,但我们不能把它“拿出”来决定采取什么行动。

关于haskell - 关于 >>= Monad 运算符的签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21221705/

相关文章:

haskell - Haskell 中是否有任何运算符可以用 (>>) 折叠操作列表?

parsing - 我如何了解解析器组合器?

scala - Scala 2.10.1 中的新脱糖行为

haskell - monad 运算符名称的继承

haskell - 为什么 XMonad 的提示对我不起作用?

haskell - 绑定(bind)多个参数

haskell - 为什么具有多个生成器的 Haskell 列表推导将最右边的生成器视为最紧密的循环?

haskell - 如何使用reader monad的函数实例?

haskell - 部分应用的中缀运算符的名称 "section"来自哪里?

haskell - ApplicativeDo 不使用测序