nub -6ren">
gpt4 book ai didi

haskell - 如何停止 GHCi 中的无限评估?

转载 作者:行者123 更新时间:2023-12-02 01:31:18 27 4
gpt4 key购买 nike

当我运行类似的东西时:

Prelude> cycle "ab"

我可以看到“ab”的无限打印。要停止它,我只需使用 Ctrl+c。它有效。

当我运行时:
Prelude Data.List> nub $ cycle "ab"

我无法阻止它。

问题:
  • 为什么会这样?
  • 如何停止此操作?

  • 更新:
     Ubuntu: version 18.10  
    GHCi: version 8.2.2

    最佳答案

    好问题!但是,由于 How to abort execution in GHCI?已经关注你的第二部分了,这里不再赘述。相反,让我们专注于第一个。

    Why it so?



    GHC 积极优化循环。如果没有分配 that it's even a known bug,它会进一步优化它们:

    19.2.1. Bugs in GHC

    • GHC’s runtime system implements cooperative multitasking, with context switching potentially occurring only when a program allocates. This means that programs that do not allocate may never context switch. This is especially true of programs using STM, which may deadlock after observing inconsistent state. See Trac #367 for further discussion. [emphasis mine]

      If you are hit by this, you may want to compile the affected module with -fno-omit-yields (see -f*: platform-independent flags). This flag ensures that yield points are inserted at every function entrypoint (at the expense of a bit of performance).



    如果我们检查 -fomit-yields , 我们发现:

    -fomit-yields

    Default: yield points enabled

    Tells GHC to omit heap checks when no allocation is being performed. While this improves binary sizes by about 5%, it also means that threads run in tight non-allocating loops will not get preempted in a timely fashion. If it is important to always be able to interrupt such threads, you should turn this optimization off. Consider also recompiling all libraries with this optimization turned off, if you need to guarantee interruptibility. [emphasis mine]


    nub $ cycle "ab"是一个紧密的、非分配的循环,尽管 last $ repeat 1是一个更明显的非分配示例。

    “已启用屈服点”具有误导性: -fomit-yields默认启用。由于标准库是用 -fomit-yields 编译的, 标准库中所有导致紧密、非分配循环的函数可能会在 GHCi 中显示这种行为,因为您永远不会重新编译它们。

    我们可以使用以下程序来验证:
    -- Test.hs
    myLast :: [a] -> Maybe a
    myLast [x] = Just x
    myLast (_:xs) = myLast xs
    myLast _ = Nothing

    main = print $ myLast $ repeat 1

    如果在 GHCi 中运行,我们可以使用 C-c 退出它无需预先编译 :
    $ ghci Test.hs
    [1 of 1] Compiling Main ( Test.hs, interpreted )
    Ok, one module loaded.
    *Main> :main <pressing C-c after a while>
    Interrupted.

    如果我们编译它然后在 GHCi 中重新运行它,它会挂起:
    $ ghc Test.hs
    [1 of 1] Compiling Main ( Test.hs, Test.o )
    Linking Test.exe ...

    $ ghci Test.hs
    Ok, one module loaded.
    *Main> :main
    <hangs indefinitely>

    请注意,您需要 -dynamic如果您不使用 Windows,否则 GHCi 将重新编译源文件。但是,如果我们使用 -fno-omit-yield ,我们突然又可以退出了(在 Windows 中)。

    我们可以用另一个小片段再次验证:
    Prelude> last xs = case xs of [x] -> x ; (_:ys) -> last ys
    Prelude> last $ repeat 1
    ^CInterrupted

    ghci不使用任何优化,也不使用 -fomit-yield (因此启用了 -fno-omit-yield)。我们的 last 的新变体不会产生与 Prelude.last 相同的行为因为它不是用 fomit-yield 编译的.

    现在我们知道为什么会发生这种情况,我们知道我们将在整个标准库中体验到这种行为,因为标准库是使用 -fomit-yield 编译的。 .

    关于haskell - 如何停止 GHCi 中的无限评估?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55188787/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com