【问题标题】:Why does this code require the Monad constraint?为什么这段代码需要 Monad 约束?
【发布时间】:2014-08-29 10:21:57
【问题描述】:

在使用 monad 转换器构建 monad 堆栈以编写库时,我遇到了一个关于它的行为的问题。

以下代码不会通过类型检查器:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Foo (FooM, runFooM, foo) where

import Control.Applicative
import Control.Monad.Reader

newtype FooM m a = FooM { runFooM :: ReaderT Int m a }
  deriving (Functor, Applicative, Monad, MonadReader Int)

foo :: FooM m Int
foo = do
  x <- ask
  return x

错误是:

$ ghc foo.hs
[1 of 1] Compiling Foo              ( foo.hs, foo.o )

foo.hs:12:3:
    No instance for (Monad m) arising from a do statement
    Possible fix:
      add (Monad m) to the context of
        the type signature for foo :: FooM m Int
    In a stmt of a 'do' block: x <- ask
    In the expression:
      do { x <- ask;
           return x }
    In an equation for ‘foo’:
        foo
          = do { x <- ask;
                 return x }

正如 GHC 建议的那样,修复很简单,只需将 Monad 约束添加到 foo 函数即可:

foo :: Monad m => FooM m Int
foo = do
  x <- ask
  return x

但在这里,foo 函数只有 asks 的 FooM 值来赋予其 Int 值,并且它已经是(自动派生的)MonadReader 实例。 所以我认为Monad 约束不需要m

我猜这与 monad 转换器的实现有关(我使用 mlt==2.2.1), 但我无法弄清楚确切的原因。 不过,我可能会错过一些明显的东西。 你能解释一下为什么这没有通过检查器吗?

谢谢。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    这是因为ReaderTMonad 实例被定义为

    instance Monad m => Monad (ReaderT r m)
    

    即仅当内部 rmMonad 的实例时,类型 ReaderT r m 才是 Monad 的实例。这就是为什么在使用 ReaderTMonad 实例(您的 FooM 类型通过派生机制使用该实例)时,您不能拥有不受约束的 m

    【讨论】:

    • 啊!这是我错过的答案。非常感谢!
    【解决方案2】:

    returns typeMonad m =&gt; a -&gt; m a,因此需要约束。

    【讨论】:

      【解决方案3】:

      根据 monad 法则,foo ≡ ask,它确实可以在没有 Monad 约束的情况下工作。但是如果你不要求Monad,那么GHC很难根据这些规律进行简化,不是吗?当然不是 before 类型检查代码。你写的是语法糖

      foo = ask >>= \x -> return x
      

      这需要(&gt;&gt;=) :: Monad (FooM m) =&gt; FooM m Int -&gt; (Int-&gt;FooM m Int) -&gt; FooM m Intreturn :: Monad (FooM m) =&gt; Int-&gt;FooM m Int

      同样,&gt;&gt;= return 对于正确的 monad 没有任何作用,但对于非 monad,它甚至没有定义,因此不能被忽略。

      【讨论】:

        猜你喜欢
        • 2020-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-02
        • 1970-01-01
        相关资源
        最近更新 更多