haskell 为什么要用“pure”来表示“Monad”?

trnvg8h3  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(97)

我正在用https://github.com/lsmor/snake-fury/学习Haskell。exercise 4中的一个任务是“为新类型实现Applicative示例”,其中新类型是

newtype GameStep m a = GameStep {runGameStep :: ReaderT BoardInfo (StateT GameState m) a}

字符串
这是我的第一次尝试,没有编译。

instance (Applicative m) => Applicative (GameStep m) where
  pure a = GameStep $ pure a
  (GameStep r) <*> (GameStep s) = GameStep $ r <*> s


GHC说,

• Could not deduce (Monad m) arising from a use of ‘pure’
      from the context: Applicative m
        bound by the instance declaration at src/GameState.hs:55:10-52
      Possible fix:
        add (Monad m) to the context of
          the type signature for:
            pure :: forall a. a -> GameStep m a
          or the instance declaration


(and <*>使用相同)
如果我按照建议将(Applicative m) => ...替换为(Monad m) => ...,它会编译。但我不理解这个错误消息,因为pure(以及<*>)是为Applicative定义的,而不是为Monad定义的。
如有任何建议,我们将不胜感激。

kh212irz

kh212irz1#

这是因为您的m被 Package 在StateT内部(然后 Package 在ReaderT中,但这并没有增加任何内容)。
当您写入GameStep $ pure a时,pure a必须不仅返回m a,还返回ReaderT _ (StateT _ m) a
如果你查看StateT的文档,你会看到Applicative被定义为:

instance (Functor m, Monad m) => Applicative (StateT s m)

字符串
所以不是你自己的示例需要Monad,而是StateT的示例。
现在,StateT需要Monad的原因是,为了实现<*>,它需要执行两个参数,但对于StateT,执行顺序很重要,因此<*>StateT实现必须使用底层Monad>>=定义参数执行的顺序,并在它们之间线程化状态。

相关问题