MonadPlus和forever有什么关系?

6

我看到 这里

-- 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来中断它,但我的兴趣在于这个奇怪的注释。

3
例如,forever (mzero :: Maybe Int) 只返回 Nothing。对于 IOforever (mzero :: IO ()) 抛出一个错误。 - snak
2个回答

12
你可以查看forever的实现方式:
forever :: Applicative f => f a -> f b -> f b
forever a = let a' = a *> a' in a'

(*>)文档中说它会“顺序执行操作,并丢弃第一个参数的值”。它基本上是适用于应用函子而不是单子的(>>)

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

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

正如forever的描述所说,如果Applicative具有一些短路行为,它仍然可以终止而不评估无限序列的操作:

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

这是因为 (Nothing *> _) = Nothing,在 (*>) 后面的内容不会被计算,所以 Nothing *> Nothing *> Nothing *> ... 能够短路到 Nothing 而无需计算动作的无限列表。


1
"[(*>)] 基本上是一个 (>>),但它是用于 Applicatives 而不是 Monads 的。" - 它 字面上 是一个不需要 Monad 实例的 (>>) - leftaroundabout

11

有些人天真地认为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)循环更加通用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接