有3个程序我试图了解堆栈和堆中发生了什么。 都是无限循环
1
(let ((f (lambda () 'ok))
(g (lambda (a b) (a a b))))
(g g f))
所有应用程序都是尾递归 - 堆栈没问题。 只创建了2个lambda - 所以堆是可以的。 我是对的吗?
2
(let ((f (lambda (a b)
(a a (lambda () 'ok)))))
(f f (lambda () 'ok)))
所有应用程序都是尾递归 - 堆栈没问题。 关于堆:创建了无限的lambda(lambda()'ok))。 我对吗? 那么为什么内存没有被终止?
最后一次:
3
(let ((f (lambda (a b)
(a a (lambda () (b))))))
(f f (lambda () 'ok)))
2和3有什么区别?为什么在2内存终止? 如果我在正确的情况下,在一个循环中进行3次调整:
we activate this: (lambda (a b) (a a (lambda () (b)))
on (lambda (a b) (a a (lambda () (b)))
and this (lambda () 'ok) (becuse this is (b)..)
这与2相同!
答案 0 :(得分:0)
在智能编译器中,案例1和案例2是等效的。即使没有智能编译器,每次重新创建lambdas,情况2也可能创建无限数量的lambdas,但它们可以立即进行垃圾收集。所以结果是一样的:持续堆栈和堆使用。
在第3种情况下,每个新lambda都包含对前一个lambda的自由引用,因此创建的lambda中没有一个是可垃圾收集的。你仍然有不断的堆栈使用,但堆使用量会膨胀。 (一个非常聪明的编译器可以发现lambda实际上是未使用过的,并且完全消除了这一点,但是关于自由引用的一般观点仍然存在。)
编译器还可以直接用(lambda () (b))
替换b
,如果它可以证明b
已经是一个nullary(-only)过程,并且/或者它可以证明结果lambda只会以一种无效方式调用(否则,它必须添加类型和arity检查器)。同样,为了适用于您的示例,需要一个非常智能的编译器。