哈斯克尔状态monad和monadic后卫

时间:2011-04-04 17:02:06

标签: haskell

我有一个小任务来模拟涉及状态的monadic代码中的命令性循环,并且应该没有IO,任务是在条件下退出循环,这是我的尝试:

> execState (forever $ modify (+1) >>= \x -> guard $ x < 5 ) 1

所以我希望在这里得到像4这样的东西,而是得到这个神秘的信息:

<interactive>:1:43:
    No instance for (MonadPlus Data.Functor.Identity.Identity)
      arising from a use of `guard' at <interactive>:1:43-47
    Possible fix:
      add an instance declaration for
      (MonadPlus Data.Functor.Identity.Identity)
    In the first argument of `($)', namely `guard'
    In the expression: guard $ x < 5
    In the second argument of `(>>=)', namely `\ x -> guard $ x < 5'

整个事情没有后卫就可以正常工作,但出于某种原因,似乎完全讨厌防守。

UPD : 最后我让它运行,感谢hammar的类型提示。尽管它没有返回,但我知道它运行了5次,这很酷,不知道它现在有多大用处。

runStateT (forever $ do { modify (+1); x <- get; guard $ x < 5 } :: StateT Int Maybe Int) 1

2 个答案:

答案 0 :(得分:2)

正如错误消息试图告诉您的那样,guard要求您使用的monad必须是类MonadPlus类型的实例。

在此示例中,您使用的是State monad,它实际上是StateT monad之上的Identity转换器。 MonadPlusStateT个实例,但它要求基础monad也必须是MonadPlusIdentity不是。{/ p>

对于您的示例,您可以尝试类似

的内容
> let loop = modify (+1) >> get >>= \x -> if x < 5 then loop else return x in execState loop 1

答案 1 :(得分:1)

并非所有单子都支持守卫;只有那些在MonadPlus。看起来你正在使用Identity monad(可能是execState的一部分)。当守卫失败时你想发生什么?

相关问题