【问题标题】:Y-Combinator factorial in javascript works for numbers not for the Church numerals.javascript 中的 Y-Combinator 阶乘适用于数字,而不适用于 Church 数字。
【发布时间】:2015-10-28 07:18:59
【问题描述】:

我设法在 javascript 中使用 ES6 箭头函数实现 Church 编码和 Y-Combinator。但是当我试图评估阶乘函数时,

FALSE = a => b => b 
TRUE = a => b => a 

ZERO = f => z => z
ONE = f => z => f(z)
SIX = f => z => f(f(f(f(f(f(z))))))
isZERO = n => n(x => FALSE)(TRUE)
SUCC = n => f => z => f(n(f)(z))
MULT = n => m => f => z => n(m(f))(z)

PAIR = a => b => z => z(a)(b)
FIRST = p => p(a => b => a)
SECOND = p => p(a => b => b)
ZZ = PAIR(ZERO)(ZERO)
SS = p => PAIR(SECOND(p))(SUCC(SECOND(p)))
PRED = n => FIRST(n(SS)(ZZ))

FactGen = fact => n =>
  isZERO(n)
    (ONE)
    (MULT(n)(fact(PRED(n))))

Y = g => (x => g(y => x(x)(y))) (x => g(y => x(x)(y)))

Y(FactGen)(SIX) (x=>x+1)(0)

我收到“未捕获 RangeError:超出最大调用堆栈大小(…)”错误。

如果我改变 FactGen,

FactGen = fact => n => n == 0 ? 1 : n * fact(n - 1)
Y(FactGen)(6)
720

它只是工作。

我想知道的是它的教堂数字版本。 我怎样才能做到这一点?

【问题讨论】:

    标签: javascript lambda-calculus y-combinator church-encoding


    【解决方案1】:

    您的问题是 JavaScript 不是惰性求值的。具体来说,isZero "if" 在检查第一个参数是否为零之前会评估其所有参数。

    我们可以使用带有单位函数的if 来解决这个问题:

    // type Bool = a -> a -> a
    // type Lazy a = () -> a
    // IF :: Bool -> Lazy a -> Lazy a -> a
    IF = c => a => b => c(a)(b)()
    
    FactGen = fact => n =>
      IF(isZERO(n))
        (()=>ONE)
        (()=>MULT(n)(fact(PRED(n))))
    //   ^^^^
    

    或省略 IF 包装器并将布尔编码直接更改为

    // type Bool = Lazy a -> Lazy a -> a
    FALSE = a => b => b()
    TRUE = a => b => a()
    

    【讨论】:

    • 非常感谢。贝尔吉。 FactGen = fact => n => isZERO(n) (() => ONE) (() => MULT(n)(fact(PRED(n)))) 成功了!
    猜你喜欢
    • 2012-12-04
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    相关资源
    最近更新 更多