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

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

问题描述

考虑以下Lua代码:



<预类=郎LUA prettyprint-覆盖> F = {}

对于i = 1,10做
F [I] =功能()
打印(我...)



对于k = 1,10做
F [K]()

此打印从1到10的数字。在这种情况下, I 被关闭在为外部循环的每次迭代的值。这是我一直明白倒闭了,我很高兴......



......直到我被移植了一些Lua代码到C#,我试图做同样的事情:



<预类=郎CSHARP prettyprint-覆盖> 变种F =新的操作[10];

的for(int i = 0;我小于10;我++)
{
F [I] =(新动作(委托()
{
Console.Write第(i +);
}));
}
的for(int k = 0; K< 10; k ++)
{
F [K]();
}



而现在我得到的印刷数量10倍(让我们忘记了LUA阵列是基于1)。它实际发生,在这种情况下,封闭件的工作原理上,这使得有很大的意义,因为我只调用函数一旦第一循环结束的变量,而不是它的值,



JavaScript的似乎有相同的语义(接近过变量):



<预类=郎咸平的JavaScript prettyprint-覆盖> 变种F = []

为(VAR I = 0;我小于10;我++)
{
F [I] =功能()
{
的document.write第(i +'');
};
}

为(VAR K = 0; K< 10; k ++)
{
F [K]();
}



其实,这两种行为做出很大的意义,但是当然是不相容的。



如果有一个正确的方式做到这一点,那么无论LUA,或C#和JavaScript是错误的(我还没有与其他语言的尝试还)。所以我的问题是:什么是正确



编辑闭合循环中变量的语义?:我不是问如何修理这。我知道我可以添加一个局部变量的循环中,并关闭了一个获得在C#/ JavaScript中的LUA行为。我想知道什么是关闭的理论上正确含义在一个环形变量,以及加分,其中语言实现每路封闭的短名单。



编辑:要重组我的问题:什么是关在一个环形变量演算的行为


解决方案

中的Lua手册解释到底为什么这个工程。它描述了一个while循环,因为这方面的for循环索引:

 为V = E1,E2,E3做块结束

--Is等价于:


局部变量,限制步= tonumber(E1),tonumber(E2),tonumber(E3)
如果不(var和极限和工序),然后误差()结束
同时(步骤> 0和变种&下; =极限)或(步骤下; = 0和变种> =极限)做
当地时间v =变量
地块
VAR = VAR +步


注意,此时的循环变量 v 声明的 的内部范围的循环。这是专门做来允许你在做什么。


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

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...

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

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 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.

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?"

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.

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

解决方案

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

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天全站免登陆