【问题标题】:factorial function for Church numeralsChurch 数字的阶乘函数
【发布时间】:2012-12-04 01:24:08
【问题描述】:

我正在尝试实现 Lambda-calculus, Combinators and Functional Programming 中描述的阶乘 lambda 表达式

那里的描述方式是:

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-zeroonemultiplypredecessor 是为标准教会数字定义的。实际定义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)))))))

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

问题 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 总是用nf 调用,这似乎真的很奇怪

【问题讨论】:

    标签: clojure lambda functional-programming factorial y-combinator


    【解决方案1】:

    fac-mine 的主体看起来不对:它调用(is-zero n one) 是为了产生副作用,然后无条件地调用(multiply n (f (predecessor n)))。大概你在这里想要一个条件选择(虽然我不明白为什么这不会引发一个 arity 异常,给定你对is-zero 的定义)。

    【讨论】:

    • 对不起。我在复制代码时犯了一个错误。我现在已经更正了。但我认为无条件致电multiply 的观点仍然成立。有没有办法让它变得懒惰?
    • 请注意,在 Church 数字上定义阶乘不需要递归(使用定点运算符)。
    猜你喜欢
    • 1970-01-01
    • 2011-01-26
    • 2021-01-17
    • 2022-06-24
    • 2011-07-05
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多