用 Python 實現 Y Combinator
會想要寫這個主題,主要是由於 聽說是某天很夯的 fibonacci number XD 討論中,談到了 Y Combinator,我試著用 Python 實現了一個,過程中有些想法,想要略做記錄一下。有關於 Fixed Point 與 Y Combinator 的推導,可以先參考 〈函数式编程 – FUNCTIONAL PROGRAMMING〉,如果你不想花太多時間看推導,那就來看看接下來的 Python 程式碼實作,從中瞭解如何實作 Y Combinator。 先來個簡單的開始,如何用遞迴寫個計算階乘的函式? def fact(n): return 1 if(n < 2) else n * fact(n - 1) 這樣是定義一個 lambda fact: lambda n: 1 if n < 2 else n * fact(n - 1) 這個 在 聽說是某天很夯的 fibonacci number XD 中就完成了讓 不過,階乘與費式數這兩個需求下的函式有沒有可能是同一個?也許是吧!總之,先來看看階乘時會需要的函式是什麼,假設定義為 def y(f): # 假設存在一個 fact return f(fact) 因為 def y(f): fact = lambda n: f(fact)(n) return f(fact) 很取巧對吧!只是把變數 def y(f): def get_f(): # 假設都用匿名函式實現 ... return get_f() 實際上, def y(f): def get_f(): fact = lambda n: f(fact)(n) return f(fact) return get_f() 要騙就騙到底好了,既然 def y(f): def get_f(): fact = lambda n: get_f()(n) return f(fact) return get_f() 咦?好像不用 def y(f): def get_f(): return f(lambda n: get_f()(n)) return get_f() 只不過, ... def get_f(get_f): return f(lambda n: get_f(get_f)(n)) ... 那麼原先的 def y(f): def get_f(get_f): return f(lambda n: get_f(get_f)(n)) return get_f(get_f) 然後改為 def y(f): get_f = lambda get_f: f(lambda n: get_f(get_f)(n)) return get_f(get_f) 既然 def y(f): get_f = lambda get_f: f(lambda n: get_f(get_f)(n)) return (lambda get_f: f(lambda n: get_f(get_f)(n)))(lambda get_f: f(lambda n: get_f(get_f)(n))) 既然如此,那 def y(f): return (lambda get_f: f(lambda n: get_f(get_f)(n)))(lambda get_f: f(lambda n: get_f(get_f)(n))) 咦?沒有變數了?只剩下參數 y = lambda f: (lambda x: f(lambda n: x(x)(n)))(lambda x: f(lambda n: x(x)(n))) 這就是我們想要的了, y(lambda fact: lambda n: 1 if n < 2 else n * fact(n - 1))(5) # 120 要不要自己試著也來推導一個可傳回遞迴費式數計算的函式呢?結果其實會是相同的,也就是說,上頭這個 y(lambda fib: lambda n: n if(n == 0 or n == 1) else fib(n - 1) + fib(n - 2))(10) # 55 好玩對吧!Y Combinator 看來很神奇,像是可以運行程式的程式(a program that runs programs),美國有間創投公司命名為 Y Combinator,因為它們覺得自己就類似可運行程式的程式 Y Combinator,只不過它們是間協助新創公司的公司。 實用性呢?好像沒有!不過我在這過程中玩得很高興就是了,因為很久前看過 Y Combinator 這名詞出現過幾次了,只不過一直沒去細究它,直到有人在 聽說是某天很夯的 fibonacci number XD 又提到 Y Combinator,我才好奇,原先我實作的版本會跟 Y Combinator 有什麼關係,進一步地,想試著用 Python 來玩玩看! 一切都只是為了有趣!… XD
|
LungZeno
12/24
是否實用,我沒有驗證過。但能想到 Y Combinator 幾個用處。
1、在環境受限的情況下使用。當不支援具名 lambda , closure 支援又有限,例如 PHP 5.3 。
2、解耦合。Y Combinator 的做法其實把遞迴功能分離了出來,就像各種純函數式語言一樣,功能分得細細的。有更高組合性,能做出更多預製組件,更厲害的程式碼復重。
3、Inversion of control,提供遞迴功能。對於無法或不便修改的已有函式,如果接收回呼函式,則有機會能以 Y Combinator 這類方式修改。
12/24
一般的遞迴每次遞迴只需要一個function call,使用Y Combinator會需要四次。如果function call的效率不好(例如PHP),使用上還是要考慮。