[英]Interesting recursive lambda example
我偶然發現了一個有趣的遞歸lambda示例,但我並不真正理解為什么它會以這種方式工作。
rec = lambda x : 1 if x==0 else rec(x-1)*x
f = rec
rec = lambda x: x+1
print(f(10))
在javascript中也一樣。
var rec = function(a) { if (a == 0) return 1; return rec(a - 1) * a; } var f = rec rec = function(a) { return a + 1; } console.log(f(10));
令我驚訝的是,這兩張紙都打印了100張而不是10張! (正如我所期望的)。
為什么重新分配rec會改變f函數的行為? 當在lambda中捕獲rec變量時,它不是引用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變量的機制。
我自己為一個班級項目編寫了一個解釋器,並且遇到了相同的問題,即何時何地綁定這些變量。 因此,我想了解它如何在流行語言中實現相似的功能。
您可以添加一些console.log
並查看,首先用10
調用f
,然后用9
調用rec
,結果為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));
我將為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
后續函數調用將使用在函數調用中查找的最新記錄。
f(10) #100
PS。 完整的代碼添加如下:
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
這3條語句可以總計為一條語句
rec = lambda x : 1 if x==0 else rec(x-1)*x
f = rec
rec = lambda x: x+1
從1和2
f = lambda x : 1 if x==0 else rec(x-1)*x
從上方和3
f = lambda x : 1 if x==0 else x*x
我建議您正確使用變量名,在這里您不需要重新分配
為什么使用第二條記錄而不是第一條記錄?
好吧,您的函數調用是在rec分配后發生的,因此您在rec中擁有最新的值
rec = function(a) {
return a + 1;
}
var f = function(a) { if (a == 0) return 1; return rec(a - 1) * a; } var rec = function(a) { return a + 1; } console.log(f(10));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.