闭包是由代码指针和环境指针组成的一对。环境指针包含给定函数的所有自由变量。例如:
fun f(a, b) =
let fun g(c, d) = a + b + c + d
in g end
val g = f(1, 2)
val result = g(3, 4) (*should be 10*)
功能g
包含两个自由变量:a
and b
。如果您不熟悉术语自由变量,它是未在函数范围内定义的变量。在此背景下,为了关闭某物,意味着从函数中删除任何出现的自由变量。上面的例子为闭包提供了很好的动机。当函数f
返回,我们需要能够记住的值是什么a
and b
留待以后。编译的方式是处理函数g
作为代码指针和包含所有自由变量的记录,例如:
fun g(c, d, env) = env.a + env.b + c + d
fun f(a, b, env) = (g, {a = a, b = b})
val (g, gEnv) = f(1, 2)
val result = g(3, 4, gEnv)
当我们应用该函数时g
,我们提供调用函数时返回的环境f
。请注意,现在功能g
不再出现任何未在其范围内定义的变量。我们通常将没有任何自由变量的术语称为closed。如果您仍然不清楚,Matt Might 对闭包转换有一个非常深入的解释:http://matt.might.net/articles/closure-conversion/ http://matt.might.net/articles/closure-conversion/
Javascript 中的相同示例
关闭转换前
function f(a, b){
function g(c, d) {
return a + b + c + d
}
return g
}
var g = f(1, 2)
var result = g(3, 4)
闭包转换后:
function g(c, d, env) {
return env.a + env.b + c + d
}
function f(a, b, env) {
return [g, {"a": a, "b": b}]
}
var [g, gEnv] = f(1, 2)
var result = g(3, 4, gEnv)