我看到这里
-- 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.
说实话我不明白这个注释。他们是否意味着可以用
forever
来打破 MonadPlus
,例如 - IO Bool
?假设,IO False
会破坏它...
从某一角度来看,
IO
也是MonadPlus
。也许我必须用其他东西包裹我的IO Bool
才能实现用forever
和IO Bool
打破MonadPlus
的可能性?注释到底是什么意思?
当然,我可以例外地打破它或实现自己的
forever
,但我的兴趣在于这个奇怪的注释。
你可以看看
forever
是如何实现的:
forever :: Applicative f => f a -> f b -> f b
forever a = let a' = a *> a' in a'
(*>)
的文档说它“序列操作,丢弃第一个参数的值”。它基本上是 Applicatives 而不是 Monad 的 (>>)
。
因此,如果您查看
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
而无需评估无限的操作列表。
人们可能天真地认为
forever m
会永远持续下去:
forever m = m >> forever m
= m >> m >> forever m
= m >> m >> m >> ... -- forever
但是评论提到有一些方法可以打破循环,并且
mzero
是一个简洁的示例,它以等式方式演示了情况,而不是通过操作性地考虑异常。 mzero
满足所有 mzero >> w = mzero
w
,因此:
forever mzero = mzero >> forever mzero
= mzero
重点是,monad 的选择使得
forever
比命令式语言中单纯的 while (true)
循环更加通用。