闭包对循环变量的正确语义是什么?

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演算中的循环变量的行为是什么?"

Nic*_*las 5

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环.这是专门为了准备你正在做的事情而完成的.