haskell - 在 Haskell 的绑定(bind)运算符中使用 return (>>=)

标签 haskell functional-programming monads

这是>>=的类型:

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

它需要一个函数作为第二个参数。

这是返回的类型:

return :: Monad m => a -> m a

返回m a

这显然是类型检查:

(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= (\_ -> y)

但是为什么下面的类型检查和工作方式与上面的代码类似?

(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= return y

这里 return y 应该是 m a 类型,而不是 a -> m a 类型。那么它为什么有效呢?

最佳答案

你实际上在这里混合了两个不同的单子(monad),这就是正在发生的事情。 x >>= return y在这种情况下统一为

(>>) :: ∀ m a b . Monad m => m a -> m b -> m b
x >> y = x >>= (return :: m b -> a -> m b) y
       -- aka  return :: (m b) -> (a->) (m b)

其中 returnMonad (a->) 中实现实例:

instance Monad (->) a where
  return x = \_ -> x
  ...

它与Monad m没有任何关系。实例。

至于为什么这个return在函数 monad 中运行:return :: m b -> a -> m b在编译器开始推理类型类实例之前从环境中推断出来。现在,输入 m b -> a -> m b ,即m b -> (a->m b) ,其形式为 mb -> amb 。签名return :: Monad μ => α -> μ α因此使编译器匹配 μ α ~ amb ~ a->m b 。只有此时编译器才会真正选择 return 的 monad 实例。 ,它是通过观察 a -> m b 来做到这一点的确实具有 μ α 的形式,与 μ ~ (a->)α ~ m b 。因此,它必须是 (a->)单子(monad)。

关于haskell - 在 Haskell 的绑定(bind)运算符中使用 return (>>=),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38293959/

相关文章:

haskell - 递归置换函数总是返回空列表

haskell - 在类型安全向量上使用归纳定义的应用实例

haskell - 各个角度的单子(monad)——数学的、图表的和程序化的

java - 使用 scala 模式匹配而不是 java switch case 有什么优势?

php - 在 PHP 中编写更少的类 Java 对象和更多类似于 Clojure 的函数式编程原则的代码,我应该遵循什么原则?

parsing - 生成解析器,在另一个解析器的输出上运行接收到的解析器并单子(monad)连接结果

haskell - Reader monad 可以做哪些应用函数不能做的事情?

scala - 中断或短路 Scala 中的折叠

haskell - 设计一元类型

haskell - Monad 变压器 : troubles defining bind due to different monads