我試圖在書中描述來實現的階乘lambda表達式階乘功能Lambda-calculus, Combinators and Functional Programming爲Church數
它描述的方法有:
fact = (Y)λf.λn.(((is-zero)n)one)((multiply)n)(f)(predecessor)n
Y = λy.(λx.(y)(x)x)λx.(y)(x)x
其中
(x)y is equivalent to (x y) and
(x)(y)z is equivalent to (x (y x)) and
λx.x is equivalent to (fn [x] x)
和is-zero
,one
,multiply
和predecessor
被定義爲標準教堂數字。實際定義here。
我翻譯的是以下
(defn Y-mine [y] ; (defn Y-rosetta [y]
((fn [x] (y (x x))) ; ((fn [f] (f f))
(fn [x] ; (fn [f]
(y ; (y (fn [& args]
(x x))))) ; (apply (f f) args))))))
和
(def fac-mine ; (def fac-rosetta
(fn [f] ; (fn [f]
(fn [n] ; (fn [n]
(is-zero n ; (if (zero? n)
one ; 1
(multiply n (f (predecessor n))))))) ; (* n (f (dec n)))))))
註釋掉版本相當於FAC和Y功能從Rosetta code。
問題1:
我在外地讀了該Y-rosetta
β-減少了Y-mine
理解。在這種情況下,爲什麼最好使用那一個呢?
問題2:
即使我使用Y-rosetta
。我得到的StackOverflowError當我嘗試
((Y-rosetta fac-mine) two)
而
((Y-rosetta fac-rosetta) 2)
工作正常。
無保留遞歸在哪裏發生?
我懷疑這與if
窗體在clojure中的工作方式有關,它與我的is-zero
實現不完全等價。但我一直無法自己找到錯誤。
謝謝。
更新:
考慮到@ amalloy的回答,我改變fac-mine
稍微採取懶惰的參數。我不是很熟悉clojure,所以這可能不是正確的做法。但是,基本上,我讓is-zero
採用匿名零參數函數並評估返回值。
(def lazy-one (fn [] one))
(defn lazy-next-term [n f]
(fn []
(multiply n (f (predecessor n)))))
(def fac-mine
(fn [f]
(fn [n]
((is-zero n
lazy-one
(lazy-next-term n f))))))
現在我得到一個錯誤說:
=> ((Y-rosetta fac-mine) two)
ArityException Wrong number of args (1) passed to: core$lazy-next-term$fn clojure.lang.AFn.throwArity (AFn.java:437)
這似乎很奇怪的考慮lazy-next-term
總是調用n
和f
對不起。我錯誤地複製了代碼。我現在糾正了它。但我認爲無條件地稱爲「乘法」的觀點仍然存在。有沒有辦法讓這種懶惰? – rjsvaljean