gpt4 book ai didi

haskell - 为什么 Haskell 中的 `forever` 是这样实现的?

转载 作者:行者123 更新时间:2023-12-04 18:10:59 24 4
gpt4 key购买 nike

Haskell 提供了一个方便的函数forever无限期地重复一元效应。它可以定义如下:

forever :: Monad m => m a -> m b
forever ma = ma >> forever ma
但是,在标准库中,函数是 defined不同:
forever :: Monad m => m a -> m b
forever a = let a' = a *> a' in a'
let 绑定(bind)用于强制“此处显式共享,因为它可以防止空间泄漏而不管优化如何”(来自对实现的评论)。
你能解释一下为什么第一个定义可能存在空间泄漏吗?

最佳答案

执行引擎从指向您的循环的指针开始,并根据需要延迟扩展它以找出 IO下一步要执行的 Action 。根据您对 forever 的定义,这是循环的几次迭代,就像“存储在内存中的对象”一样:

1.
PC
|
v
forever
|
v
ma

2.
PC
|
v
(>>) --> forever
| /
v L------/
ma

3.
PC
|
v
(>>) --> forever
| /
v L-----/
ma

4.
PC
|
v
(>>) --> (>>) --> forever
| / /
v L-----/----------/
ma

5 and 6.
PC
|
v
(>>) --> (>>) --> (>>) --> forever
| / / /
v L-----/--------/----------/
ma
结果是,随着执行的继续,您将获得越来越多的 (>>) 副本。细胞。在正常情况下,这没什么大不了的;没有对第一个单元格的引用,因此当垃圾收集发生时,已经执行的前缀被丢弃。但是,如果我们不小心将无限循环传递为 ma 怎么办? ?
1.
PC
|
v
forever
|
v
forever
|
v
ma

2.
PC
|
v
(>>) -> forever
| /
v L------/
forever
|
v
ma

3.
return here
when done
|
v
(>>) --> forever
| /
v L-------/
PC --> forever
|
v
ma

4.
return here
|
v
(>>) --> forever
| /
v L-------/
PC --> (>>) --> forever
| /
v L-------/
ma

like, 12ish.
return here
|
v
(>>) --> forever
| /
v L-------/
(>>) --> (>>) --> (>>) --> (>>) --> (>>) --> forever <-- PC
| / / / / /
v L-----/--------/--------/--------/----------/
ma
这次我们不能对前缀进行垃圾收集,因为一个“堆栈帧”向上,我们有一个指向顶层 forever 的指针, 仍然是指第一个 (>>) !哎呀。更高级的定义通过内存循环来解决这个问题。那里, forever ma的对象看起来更像这样:
  /----\
v |
(*>) --/
|
v
ma
现在没有额外的 (*>)需要在执行过程中被分配(也不是垃圾收集)——即使我们嵌套它们。执行指针将简单地在该图中四处移动。

关于haskell - 为什么 Haskell 中的 `forever` 是这样实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70990108/

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