为什么函数式编程语言需要垃圾回收?


14

是什么阻止ghc将Haskell转换为连接编程语言(例如组合逻辑),然后仅对所有内容使用堆栈分配?根据Wikipedia的说法,从lambda演算到组合逻辑的转换是微不足道的,而且,级联编程语言可以仅依靠堆栈来进行内存分配。进行这种翻译从而消除Haskell和ocaml等语言的垃圾回收是否可行?这样做有不利之处吗?

编辑:移到这里/programming/39440412/why-do-functional-programming-languages-require-garbage-collection


猫程序设计语言看起来像一个功能,基于堆栈的语言的例子。
PetrPudlák'16

1
不是研究级别的问题,因为垃圾回收在编程语言的本科课程中有所涉及(及其需求)。请移至cs.stackexchange.com
Andrej Bauer

我的错。你知道我的问题的答案吗?
Nicholas Grasevski

5
我认为这个问题会有一定的研究水平的回应,因为我也记得在我的研究生时代也为此感到挣扎:像Haskell 这样的语言中的所有内容都看起来像一个函数应用程序,它一直存在于堆栈中。我认为,解释为什么必须使用闭包,为什么闭包存在于堆中以及也许“数据转义函数作用域”与之相关的问题会提供非常有用的答案(我不确定我是否有资格给出答案,不幸)。
Cody

2
λ

Answers:


16

以下所有注释均以选择使用闭包表示函数值和按值调用评估顺序的标准实现策略为前提:

  1. 对于纯lambda演算,不需要垃圾回收。这是因为不可能在堆中形成循环:每个新分配的值只能包含对先前分配的值的引用,因此内存图形成DAG-因此引用计数足以管理内存。

  2. 大多数实现不使用引用计数有两个原因。

    1. 它们支持一种指针类型(例如refML中的类型构造函数),因此可以在堆中形成真正的循环。
    2. 引用计数比垃圾收集效率低得多,因为
      • 它需要很多额外的空间来保持引用计数,并且
      • 更新计数通常是浪费的工作,并且
      • 计数的更新会产生大量写入争用,这会破坏并行性能。
  3. 线性类型的语言可以消除引用计数(本质上是因为计数为0-1:要么该值具有单个引用,要么该值无效且可以释放)。

  4. 但是,堆栈分配仍然不够。这是因为有可能形成引用自由变量的函数值(即,我们需要实现函数闭包),如果您在堆栈上分配内容,则活动值可能与无效值交错,这将导致不正确的渐近空间使用情况。

  5. 您可以通过用“意大利面条堆栈”代替堆栈来获得正确的渐近性(即,将堆栈实现为堆中的链接列表,以便可以根据需要剪切掉死帧)。

  6. 如果您想要一个真正的堆栈规则,则可以使用基于“有序逻辑”的类型系统(本质上是线性类型减去交换)。


2
难道不是(2)的更基本原因-即使没有明显的副作用-实现也希望有一个有效的(相互)递归运算符,即实际上在堆中形成循环的运算符?
安德烈亚斯·罗斯伯格

@andreasrossberg:我本来想提一提,但由于可以使用y组合器进行递归,因此省略了它。
Neel Krishnaswami
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.