MonadPlus 和forever——有什么关系?

Pau*_*-AG 6 haskell

我看到这里

-- 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.
Run Code Online (Sandbox Code Playgroud)

说实话,我不太明白这个注释。他们是否意味着可以打破foreverMonadPlus例如 - IO Bool?就说吧,IO False会打破它...

从某一方面来说IO也是MonadPlus如此。也许我必须用其他东西包裹我才能实现与andIO Bool决裂的可能性?这条注释到底是什么意思?foreverIO BoolMonadPlus

当然,我可以例外地打破它或实现自己的,forever但我的兴趣在于这个奇怪的注释。

Gia*_*eri 12

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

forever :: Applicative f => f a -> f b -> f b
forever a = let a' = a *> a' in a'
Run Code Online (Sandbox Code Playgroud)

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

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

forever a = a *> a *> a *> ...
Run Code Online (Sandbox Code Playgroud)

正如forever描述所述,如果应用程序有一些短路行为,它仍然可以终止并且不评估无限的操作序列:

ghci> forever $ Nothing
Nothing
ghci> forever $ Just 1
-- infinite loop trying to evaluate Just 1 *> Just 1 *> Just 1 *> ...
Run Code Online (Sandbox Code Playgroud)

这是因为(Nothing *> _) = Nothing后面的内容(*>)甚至都没有被评估,因此无需评估无限的操作列表Nothing *> Nothing *> Nothing *> ...即可短路。Nothing


Li-*_*Xia 11

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

forever m = m >> forever m
          = m >> m >> forever m
          = m >> m >> m >> ...  -- forever
Run Code Online (Sandbox Code Playgroud)

但评论提到有一些方法可以打破循环,并且mzero是一个简洁的示例,它以等式方式演示了情况,而不是通过操作性地考虑异常。mzero满足mzero >> w = mzero所有人w,因此:

forever mzero = mzero >> forever mzero
              = mzero
Run Code Online (Sandbox Code Playgroud)

关键是,单子的选择forever比命令式语言中的单纯循环更加通用while (true)