【專欄】康托爾、哥德爾、圖靈——永恒的金色對角線(7)

Y是一個lambda函數,它接受一個偽遞歸F,在內部生成一個f_gen,然后把f_gen應用到它自身(記得power_gen(power_gen)吧),得到的這個f_gen(f_gen)也就是F的不動點了(因為f_gen(f_gen) = F(f_gen(f_gen))),而根據不動點的性質,F的不動點也就是那個對應于F的真正的遞歸函數!

鑄造Y Combinator

現在我們終于可以鑄造我們的Y Combinator了,Y Combinator只要生成一個形如power_gen的lambda函數然后把它應用到自身,就大功告成:

let Y = lambda F.

let f_gen = lambda self. F(self(self))

return f_gen(f_gen)

稍微解釋一下,Y是一個lambda函數,它接受一個偽遞歸F,在內部生成一個f_gen(還記得我們剛才看到的power_gen吧),然后把f_gen應用到它自身(記得power_gen(power_gen)吧),得到的這個f_gen(f_gen)也就是F的不動點了(因為f_gen(f_gen) = F(f_gen(f_gen))),而根據不動點的性質,F的不動點也就是那個對應于F的真正的遞歸函數!

作者:劉未鵬 出版:電子工業出版社

如果你還覺得不相信,我們稍微展開一下看看,還是拿階乘函數說事,首先我們定義階乘函數的偽遞歸版本:

let Pwr = lambda self n. If_Else n==0 1 n*self(n-1)

讓我們把這個Pwr交給Y,看會發生什么(根據剛才Y的定義展開吧):

Y(Pwr) =>

let f_gen = lambda self. Pwr(self(self))

return f_gen(f_gen)

Y(Pwr)的求值結果就是里面返回的那個f_gen(f_gen),我們再根據f_gen的定義展開f_gen(f_gen),得到:

Pwr(f_gen(f_gen))

也就是說:

Y(Pwr) => f_gen(f_gen) => Pwr(f_gen(f_gen))

我們來看看得到的這個Pwr(f_gen(f_gen))到底是不是真有遞歸的魔力。我們展開它(注意,因為Pwr需要兩個參數,而我們這里只給出了一個,所以Pwr(f_gen(f_gen))得到的是一個單參(即n)的函數):

Pwr(f_gen(f_gen)) => If_Else n==0 1 n*f_gen(f_gen) (n-1)

而里面的那個f_gen(f_gen),根據f_gen的定義,又會展開為Pwr(f_gen(f_gen)),所以:

Pwr(f_gen(f_gen)) => If_Else n==0 1 n* Pwr(f_gen(f_gen)) (n-1) 

看到加粗的部分了嗎?因為Pwr(f_gen(f_gen))是一個接受n為參數的函數,所以不妨把它令成f(f的參數是n),這樣上面的式子就是:

f => If_Else n==0 1 n*f(n-1)

完美的階乘函數!

(待續;此文的修訂版已收錄《暗時間》一書,由電子工業出版社2011年8月出版。作者于2009年7月獲得南京大學計算機系碩士學位,現在微軟亞洲研究院創新工程中心從事軟件研發工程師工作。)

網絡編輯:謝小跳

{{ isview_popup.firstLine }}{{ isview_popup.highlight }}

{{ isview_popup.secondLine }}

{{ isview_popup.buttonText }}
午夜宅男在线,中视在线直播,毛片网站在线,福利在线网址