maybeLoeb,为什么 <<loop>> 只偶尔出现/是否可以捕获?

maybeLoeb, and why does <<loop>> occur only sometimes / is it catchable?

我在玩乐布 (https://github.com/quchen/articles/blob/master/loeb-moeb.md):

loeb :: Functor f => f (f a -> a) -> f a
loeb fs = xs where xs = fmap ($ xs) fs

我想写一个函数:

maybeLoeb :: Functor f => f (f a -> a) -> Maybe (f a)

当输入错误时,它会失败而不是进入无限循环。

我在理解 <<loop>> 异常的行为时也遇到了一些困难。如果可能我想抓住它。

进入 GHCI 时:

loeb [(!! 1),(!! 0)] :: [Int]
*** Exception: <<loop>>

但是,在loeb.hs中定义时:

main = print (loeb [(!! 1),(!! 0)] :: [Int])

然后使用 :l main 加载到 GHCI,我们得到:

*Main> :l loeb
[1 of 1] Compiling Main             ( loeb.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
[

并且程序不会终止。

<<loop>> except 可以捕捉吗?如果是这样,有没有办法让上面的第二个版本抛出异常?

存在 <<loop>> 异常是因为 GHC 为 多线程 操作设计的惰性求值实现使得一种非常特殊的无限循环形式易于检测使用 单线程 运行时系统 (RTS) 时。多线程RTS在需要强制thunk时,大致是这样的流程:

  1. 检查thunk是否已经被求值;如果是这样,请使用已知值并忽略其余部分。

  2. 检查 thunk 是否被标记为正在评估过程中。如果是这样,则该线程让出让正在该 thunk 上工作的任何线程完成其工作。返回第 0 步。

  3. 标记 thunk 以表明正在对其进行评估。

  4. 评估thunk。

  5. 存储结果并将 thunk 标记为已评估。

单线程和多线程运行时使用相同的基本过程,以避免大量代码重复。但在单线程运行时,"yield" 步骤被 <<loop>> 异常取代——如果程序试图在强制那个 thunk 的过程中强制一个 thunk,它肯定会卡住。肯定没有任何其他线程在强制 thunk 的中间。

我不确定是否可以捕获异常,但你肯定不想依赖捕获它——不同的优化级别或编译器版本可能会在不同的环境中产生异常个案。你的程序是否陷入了死循环,这个问题不能笼统地回答。正如 ,这被称为 停机问题 ,艾伦图灵著名地证明了它无法解决。