在这篇 stackoverflow 帖子 中,有一些 C++ 代码试图模仿关联类型。当 lambda 函数使用引用捕获捕获环境(闭包)时,代码可以编译,但在运行时失败。当代码更改为按值捕获时,代码在编译时和运行时都会成功。 GHC 如何通过引用或值捕获 lambda 函数的闭包?
GHC 通过引用捕获闭包中的变量,但是 (1) 因为所有值都分配在垃圾收集堆上,所以引用在闭包的生命周期内保持有效,因此不会像 C++ 示例中那样出现运行时错误; (2) 因为 Haskell 值是不可变的,所以程序的行为基本上与通过值捕获闭包相同,因为引用的值在 Haskell 程序的生命周期中不会改变。
所以,例如在程序中:
subtracter :: Integer -> (Integer -> Integer)
subtracter delta = let increment = -delta in \x -> x + increment
调用
subtracter 42
的结果是一个 lambda x -> x + increment
,它通过引用捕获了 increment
的值。 即使 increment
是一个“局部变量”(或接近 Haskell 中的局部变量),它仍然是对堆上不可变值 -42
的引用,而不是堆栈上的可变值,就像 C++ 一样。 因此,该引用在 lambda 的生命周期内保持有效,并且始终是对值 -42
的不可变引用,因此效果与 lambda “按值”捕获它一样 -42
.