循环变量上的闭包的正确语义是什么? [英] What are the correct semantics of a closure over a loop variable?

查看:25
本文介绍了循环变量上的闭包的正确语义是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的lua代码:

Consider the following lua code:

f = {}

for i = 1, 10 do
    f[i] = function()
        print(i .. " ")
    end
end

for k = 1, 10 do
    f[k]()
end

这将打印从 1 到 10 的数字.在这种情况下,i 对外部循环的每次迭代的值进行封闭.这就是我一直以来对闭包的理解,我很高兴...

This prints the numbers from 1 to 10. In this case, i is closed over the value for each iteration of the outer loop. This is how I had always understood closures, and I was very happy...

...直到我将一些 lua 代码移植到 c# 中,并且我尝试做同样的事情:

...until I was porting some lua code into c#, and I tried to do the same thing:

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]();
}

现在我将数字 10 打印了 10 次(让我们忘记 lua 数组是基于 1 的).实际上,在这种情况下,闭包对变量起作用,而不是对它的值起作用,这很有意义,因为我只在第一个循环结束后调用函数.

And now I get the number 10 printed 10 times (let's forget that lua arrays are 1-based). It actually happens that in this case, the closure works over the variable, not its value, which makes a lot of sense, since I'm only calling the functions once the first loop is over.

JavaScript 似乎具有相同的语义(关闭变量):

JavaScript seems to have the same semantics (close over the variable):

var f = []

for (var i = 0; i < 10; i++)
{
    f[i] = function()
    {
        document.write(i + ' ');
    };
}

for (var k = 0; k < 10; k++)
{
    f[k]();
}

实际上,这两种行为都很有意义,但当然不兼容.

Actually, both behaviors make a lot of sense, but are of course incompatible.

如果有一种正确"的方法可以做到这一点,那么无论是 lua 还是 c# 和 JavaScript 都是错误的(我还没有尝试过其他语言).所以我的问题是:在循环内关闭变量的正确"语义是什么?"

If there is a "correct" way to do this, then either lua, or c# and JavaScript are wrong (I haven't tried with other languages yet). So my question is: "what are the "correct" semantics of closing a variable inside a loop?"

我不是在问如何解决"这个问题.我知道我可以在循环中添加一个局部变量并关闭该变量以获得 c#/JavaScript 中的 lua 行为.我想知道关闭循环变量的理论上正确的含义是什么,以及哪些语言以每种方式实现闭包的简短列表的奖励积分.

edit: I'm not asking how to "fix" this. I know I can add a local variable inside the loop and close over that one to get the lua behavior in c#/JavaScript. I want to know what is the theoretically correct meaning of closing over a looped variable is, and bonus points for a short list of which languages implement closures in each way.

重新表述我的问题:在 lambda 演算中关闭循环变量的行为是什么?"

edit: To rephrase my question: "what is the behavior of closing over a looped variable in lambda calculus?"

推荐答案

Lua 手册解释了为什么会这样.它根据 while 循环描述了索引 for 循环,如下所示:

The Lua manual explains exactly why this works. It describes the index for-loop in terms of a while loop as this:

 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

注意循环变量 v 是如何在 while 循环的范围内声明的.这样做是为了让您的工作准确无误.

Notice how the loop variable v is declared inside the scope of the while loop. This is done specifically to allow exactly what you're doing.

这篇关于循环变量上的闭包的正确语义是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆