Pan*_*ama 1 javascript c# lua closures lambda-calculus
考虑以下lua代码:
f = {}
for i = 1, 10 do
f[i] = function()
print(i .. " ")
end
end
for k = 1, 10 do
f[k]()
end
Run Code Online (Sandbox Code Playgroud)
这将打印从1到10的数字.在这种情况下,i将关闭外部循环的每次迭代的值.这就是我一直都懂得闭合的方式,我很开心......
...直到我将一些lua代码移植到c#中,我试图做同样的事情:
var f = new Action[10];
for (int i = 0; i < 10; i++)
{
f[i] = (new Action(delegate()
{
Console.Write(i + " ");
}));
}
for (int k = 0; k < 10; k++)
{
f[k]();
}
Run Code Online (Sandbox Code Playgroud)
现在我将10号打印10次(让我们忘记了lua数组是基于1的).实际上,在这种情况下,闭包对变量起作用,而不是它的值,这很有意义,因为我只是在第一个循环结束后调用函数.
JavaScript似乎具有相同的语义(接近变量):
var f = []
for (var i = 0; i < 10; i++)
{
f[i] = function()
{
document.write(i + ' ');
};
}
for (var k = 0; k < 10; k++)
{
f[k]();
}
Run Code Online (Sandbox Code Playgroud)
实际上,这两种行为都很有意义,但当然是不相容的.
如果有一个"正确"的方法来做到这一点,那么lua,或者c#和JavaScript是错误的(我还没有尝试过其他语言).所以我的问题是:"在循环中关闭变量的"正确"语义是什么?"
编辑:我不是问如何"修复"这个.我知道我可以在循环中添加一个局部变量并关闭那个变量以获得c#/ JavaScript中的lua行为.我想知道关闭循环变量的理论正确含义是什么,以及哪些语言以各种方式实现闭包的简短列表的奖励积分.
编辑:重新解释我的问题:"关闭lambda演算中的循环变量的行为是什么?"
Lua手册解释了为什么这有效.它用while循环描述了for循环索引,如下所示:
for v = e1, e2, e3 do block end
--Is equivalent to:
do
local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
if not (var and limit and step) then error() end
while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
local v = var
block
var = var + step
end
end
Run Code Online (Sandbox Code Playgroud)
注意循环变量如何v被声明内的范围while环.这是专门为了准备你正在做的事情而完成的.