MonadPlus 和 forever - 有什么关系?

MonadPlus and forever - what is the relation?

我明白了here

-- Note that "forever" isn't necessarily non-terminating.
-- If the action is in a @'MonadPlus'@ and short-circuits after some number of iterations.
-- then @'forever'@ actually returns `mzero`, effectively short-circuiting its caller.

老实说,我不明白这个注释。它们是否意味着可以用 MonadPlus 打破 forever,例如 - IO Bool?比方说,IO False 会破坏它...

从一个角度来看 IO 也是 MonadPlus。也许我必须将我的 IO Bool 包裹在其他东西中以实现用 IO BoolMonadPlus 打破 forever 的可能性?注释到底是什么意思?

当然,我可以打破它或实现自己的 forever 但我的兴趣是关于这个奇怪的笔记。

可以看看forever是如何实现的:

forever :: Applicative f => f a -> f b -> f b
forever a = let a' = a *> a' in a'

(*>) 的文档说它“顺序操作,丢弃第一个参数的值”。它基本上是 (>>) 用于 Applicatives 而不是 Monads。

因此,如果您查看 forever 的实现方式,您会发现它基本上扩展为:

forever a = a *> a *> a *> ...

正如 forever 描述所说,如果 Applicative 有一些 short-circuiting 行为,它仍然可以终止并且不会评估无限的动作序列:

ghci> forever $ Nothing
Nothing
ghci> forever $ Just 1
-- infinite loop trying to evaluate Just 1 *> Just 1 *> Just 1 *> ...

那是因为 (Nothing *> _) = Nothing 跟在 (*>) 之后的内容甚至没有被评估,所以 Nothing *> Nothing *> Nothing *> ... short-circuits 到 Nothing 无需评估无限列表动作数。

人们可能会天真地认为 forever m 会永远持续下去:

forever m = m >> forever m
          = m >> m >> forever m
          = m >> m >> m >> ...  -- forever

但是评论提到有办法打破循环,mzero 是一个简洁的例子,它用方程式而不是从操作上考虑异常来说明情况。 mzero 满足所有 wmzero >> w = mzero,因此:

forever mzero = mzero >> forever mzero
              = mzero

重点是 monad 的选择使得 forever 比命令式语言中的单纯 while (true) 循环更加通用。