Clojure Church数词的阶乘函数

Clojure Church数词的阶乘函数,clojure,lambda,functional-programming,factorial,y-combinator,Clojure,Lambda,Functional Programming,Factorial,Y Combinator,我正试图实现书中描述的阶乘lambda表达式 这里的描述方式是: fact = (Y)λf.λn.(((is-zero)n)one)((multiply)n)(f)(predecessor)n Y = λy.(λx.(y)(x)x)λx.(y)(x)x 在哪里 而为零,一,乘法和前置是为标准的教堂数字定义的。实际定义 我把它翻译成以下内容 (defn Y-mine [y] ; (defn Y-rosetta [y] ((fn [x] (y (x

我正试图实现书中描述的阶乘lambda表达式

这里的描述方式是:

fact = (Y)λf.λn.(((is-zero)n)one)((multiply)n)(f)(predecessor)n
Y = λy.(λx.(y)(x)x)λx.(y)(x)x
在哪里

为零
乘法
前置
是为标准的教堂数字定义的。实际定义

我把它翻译成以下内容

(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))))))

注释掉的版本是来自的等效fac和Y函数

问题1:

我从别处的阅读中了解到,
Y-rosetta
β-降低为
Y-mine
。在这种情况下,为什么使用这一个优于另一个

问题2:

即使我使用
Y-rosetta
。当我尝试时,我得到了一个堆栈溢出错误

((Y-rosetta fac-mine) two)

很好

无防护递归发生在哪里

我怀疑这与
if
表单在clojure中的工作方式有关,它并不完全等同于我的
is zero
实现。但我自己还没能找到错误

谢谢

更新:

考虑到@amalloy的回答,我稍微改变了
fac-mine
以接受懒惰的论点。我对clojure不是很熟悉,所以,这可能不是正确的方法。但是,基本上,我让
为零
接受匿名零参数函数并计算它返回的任何值

(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)

考虑到
懒惰的下一个术语
总是用
n
f
调用,这看起来真的很奇怪
fac mine的主体
看起来是错误的:它调用
(是零n一)
以获得副作用,然后无条件调用
(乘以n(f(前置n))
。大概您希望在这里有一个条件选择(尽管我不明白为什么这不会引发算术异常,因为您对
的定义是零
)。

我很抱歉。我复制代码时出错了。我现在已经改正了。但我认为无条件调用
multiply
的观点仍然成立。有没有办法让你变得懒惰?
((Y-rosetta fac-rosetta) 2)
(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)