为了账号安全,请及时绑定邮箱和手机立即绑定

有趣的递归 lambda 示例

有趣的递归 lambda 示例

叮当猫咪 2021-06-16 17:09:44
我偶然发现了一个有趣的递归 lambda 示例,但我真的不明白为什么它会以这种方式工作。rec = lambda x : 1 if x==0 else rec(x-1)*xf = rec rec = lambda x: x+1print(f(10))  在javascript中相同。var rec = function(a) {  if (a == 0) return 1;  return rec(a - 1) * a;}var f = recrec = function(a) {  return a + 1;}console.log(f(10));令我惊讶的是这两个打印 100 而不是 10!(正如我所料)。为什么重新分配 rec 会改变 f 函数的行为?当 rec 变量在 lambda 中被捕获时,它不是指的是 lambda 本身吗?编辑。由于大多数答案都解释了发生了什么,让我重新表述这个问题,因为我正在寻找更深入的解释。那么在第一行中声明函数 rec 的那一刻,为什么函数体中的 rec 没有绑定到自身?例如,如果您使用 JavaScript 并按照您得到的其中一个答案中的建议,以看似“相同”的方式重写第一行:var rec =function rec(a) {    if (a == 0) return 1;    return rec(a - 1) * a;};f = rec;rec = function (a) {    return a + 1;}console.log(f(10));这个打印出10个!正如人们所期望的那样。所以在这种情况下,“内部 rec”(在函数体中)绑定到函数名的 rec 而不是查看 rec 变量,并且变量 rec 的重新分配没有改变行为。所以我真正要问的是这些语言决定在 lambda 中绑定变量的机制。我正在为一个班级项目自己编写一个解释器,我遇到了同样的问题,即何时何地绑定这些变量。所以我想了解这在流行语言中是如何工作的,以实现类似的东西。
查看完整描述

2 回答

?
开心每一天1111

TA贡献1836条经验 获得超13个赞

我将为 python 解决它,因为这是我熟悉的。


首先,这种行为是唯一可能的,因为python(并且我认为看起来像javascript)遵循其闭包的后期绑定。进一步阅读


后期绑定是在运行时查找闭包中的名称(与在编译时查找名称的早期绑定不同。)


这允许在运行时通过重新绑定在运行时查找的变量(例如像 rec 之类的函数)来改变行为。


最后一步只是将 lambda 函数转换为等效的def语法,因此实际行为更加清晰。


编码:


rec = lambda x : 1 if x==0 else rec(x-1)*x

f = rec 

rec = lambda x: x+1

print(f(10)) 

可以等价于:


第一的:


def somefunc(x):

    return 1 if x==0 else rec(x-1)*x 

请注意,即使在干净的会话/内核上,python 也不会抱怨 rec 不存在,因为它在函数定义期间不会查找值。后期绑定意味着除非调用这个函数,否则python不关心rec是什么。


然后:


rec = somefunc

f = rec


def someotherfunc(x):

    return x + 1


f(10) #3628800

现在我们改变rec函数


rec = someotherfunc

并观察随后的函数调用f将使用后期绑定 rec,即在函数调用中查找。


f(10) #100

附注。完整代码添加如下:


def somefunc(x):

    return 1 if x==0 else rec(x-1)*x


rec = somefunc


f = rec


def someotherfunc(x):

    return x + 1


f(10) #3628800


rec = someotherfunc


f(10) #100


查看完整回答
反对 回复 2021-06-24
?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

你可以添加一些console.log和看法,首先f被调用10,然后rec用9其结果是10 * 10。


var rec = function(a) {

        console.log('f', a);

        if (a == 0) return 1;

        return rec(a - 1) * a;

    };

    f = rec;


rec = function(a) {

    console.log('rec', a);

    return a + 1;

}


console.log(f(10));

保持rec.


var rec = function rec(a) {

        console.log('f', a);

        if (a == 0) return 1;

        return rec(a - 1) * a;

    };

    f = rec;


rec = function(a) {

    console.log('rec', a);

    return a + 1;

}


console.log(f(10));


查看完整回答
反对 回复 2021-06-24
  • 2 回答
  • 0 关注
  • 144 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信