- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在玩 javascript(节点)中的 lambda 演算。
我创建了一些 Church 数字,并且一直在尝试创建一个计算斐波那契数列的递归函数,但它绝对行不通!
我曾尝试将函数包装在 Y 组合器和 Z 组合器中,但它们(或我的应用程序)都不起作用。
我认为可能发生的是javascript只是应用递归函数,然后每次这样做,递归函数都会再次创建,等等。
const TRUE = a => b => a;
const FALSE = a => b => b;
const ISZERO = n => n(x=>FALSE)(TRUE);
const LEQ = m => n => ISZERO (SUB(m)(n));
const EQ = m => n => AND(LEQ(m)(n), LEQ(n)(m));
const IF = p => a => b => p(a)(b);
const ZERO = f => x => x;
const NEXT = n => f => x => f(n(f)(x));
const PLUS = m => n => f => x => m(f)(n(f)(x));
const PRE = n => f => x => n(g=> h=> h(g(f)))(u=>x)(u=>u);
const toInt = c => c((x) => x + 1)(0);
const SUB = m => n => n(PRE)(m);
const ONE=NEXT(ZERO);
const TWO=NEXT(ONE);
const THREE=NEXT(TWO);
console.log(toInt(THREE)); // returns 3
console.log(toInt(PLUS(THREE)(TWO))); // returns 5
console.log(toInt(PRE(PLUS(THREE)(TWO)))); // returns 4
// Define my Fibonacci function
const fib = x => IF(LEQ(x)(ONE))(ONE)(PLUS(fib(PRE(PRE(x))))(fib(PRE(x))));
console.log(toInt(fib(THREE))); // Doesn't work
> fib(THREE)
Thrown:
RangeError: Maximum call stack size exceeded
at NEXT.f (repl:1:19)
at x (repl:1:46)
at x (repl:1:31)
at x (repl:1:46)
at x (repl:1:46)
...
最佳答案
每个人都会同意 Church 编码会产生深度调用堆栈,但是 fib(3)
足够小它显然应该是可能的而不会导致堆栈溢出。
问题在于您的 IF
.它每次都评估 True 和 False 分支。所以在你的fib
程序,fib
总是重复。
一个简单的解决方法是延迟评估任一侧,直到评估条件,然后才评估相应的 True 或 False 分支。 IE,
IF(cond)(t => trueExpression)(f => falseExpression)
IF
,您将调用不带参数的结果分支。注意尾随
...()
–
const IF = p => a => b => p(a)(b)();
const TRUE = a => b => a;
const FALSE = a => b => b;
const ISZERO = n => n(x=>FALSE)(TRUE);
const LEQ = m => n => ISZERO (SUB(m)(n));
const EQ = m => n => AND(LEQ(m)(n), LEQ(n)(m));
const IF = p => a => b => p(a)(b)();
const ZERO = f => x => x;
const NEXT = n => f => x => f(n(f)(x));
const PLUS = m => n => f => x => m(f)(n(f)(x));
const PRE = n => f => x => n(g=> h=> h(g(f)))(u=>x)(u=>u);
const toInt = c => c((x) => x + 1)(0);
const SUB = m => n => n(PRE)(m);
const ONE=NEXT(ZERO);
const TWO=NEXT(ONE);
const THREE=NEXT(TWO);
const FOUR=NEXT(THREE);
// Define my Fibonacci function
const fib = x => IF(LEQ(x)(ONE))(_ => ONE)(_ => PLUS(fib(PRE(PRE(x))))(fib(PRE(x))));
console.log(toInt(fib(ZERO))); // 1
console.log(toInt(fib(ONE))); // 1
console.log(toInt(fib(TWO))); // 2
console.log(toInt(fib(THREE))); // 3
console.log(toInt(fib(FOUR))); // 5
IF(pred)(thenA)(elseB)
, 在我们尝试评估
IF
之前,我们必须首先评估
pred
,
thenA
, 和
elseB
.因为
fib
在
elseB
中重复出现代码部分,
fib
无论退出条件如何,都会进行热切评估,
pred
- 因此堆栈溢出。
const Variable = name =>
({ type: 'variable', name })
const Lambda = (parameter, body) =>
({ type: 'lambda', parameter, body })
const Apply = (procedure, argument) =>
({ type: 'application', procedure, argument})
const v = Variable
const l = Lambda
const a = (e, ...exprs) => exprs.reduce(Apply, e)
// before
const TRUE = a => b => a
// after
const TRUE = l('a', l('b', v('a')))
// before
const FALSE = a => b => b
// after
const FALSE = l('a', l('b', v('b')))
// before
const ISZERO = n => n(x=>FALSE)(TRUE)
// after
const ISZERO = l('n', a(v('n'), l('x', FALSE), TRUE))
toBool
接受一个表达式并返回一个 JavaScript bool 值——
toBool(a(ISZERO, church(0))) // => true
toBool(a(ISZERO, church(1))) // => false
toInt
,它接受一个表达式并返回一个 JavaScript 数字——
toInt(a(NEXT, church(7))) // => 8
church(n)
而不是预先定义
ONE
,
TWO
,
THREE
- 这使得按需构建任何教堂数字变得容易 -
const NEXT =
l('n', l('f', l('x', a(v('f'), a(v('n'), v('f'), v('x'))))))
const ZERO = l('f', l('x', v('x')))
const church = n => n === 0 ? ZERO : a(NEXT, church(n-1))
const ONE = NEXT(ZERO) // same as church(1)
const TWO = NEXT(ONE) // same as church(2)
const THREE = NEXT(TWO) // same as church(3)
toInt(a(NEXT, church(9))) // => 10
toBool(a(EQ, church(5), a(NEXT, church(4)))) // => true
Variable
、
Lambda
或
Apply
)。我们将选择正常顺序策略
call by name –
Call by name is an evaluation strategy where the arguments to a function are not evaluated before the function is called—rather, they are substituted directly into the function body (using capture-avoiding substitution) and then left to be evaluated whenever they appear in the function. If an argument is not used in the function body, the argument is never evaluated; if it is used several times, it is re-evaluated each time it appears.
const evaluate = (env, expr) => {
switch (expr.type) {
case 'variable':
return env[expr.name]() // force evaluation
case 'lambda':
return x =>
evaluate
( { ...env, [expr.parameter]: x }
, expr.body
)
case 'application':
return evaluate
(env, expr.procedure) // eval the func
(_ => evaluate (env, expr.argument)) // delay the argument
default:
throw Error(`unsupported expression: ${expr}`)
}
}
toBool
和
toInt
.注意
toInt
的相似性与您问题中的代码相比 - 这里略有不同,因为评估策略不同 -
// before
const toInt = c => c((x) => x + 1)(0);
// after
const toInt = expr =>
evaluate ({}, expr) (_ => x => x () + 1) (_ => 0)
// a new evaluator type
const toBool = expr =>
evaluate ({}, expr) (_ => true) (_ => false)
FIB
.注意这个实现允许使用
IF
无需人为地延迟任何一个分支——
// before
const fib = x =>
IF(LEQ(x)(ONE))
(_ => x)
(_ => PLUS(fib(PRE(PRE(x))))
(fib(PRE(x))))
// after
const FIB =
l('r', l('x', a(
IF,
a(LEQ, v('x'), church(1)),
v('x'),
a(
PLUS,
a(v('r'), a(PRE, v('x'))),
a(v('r'), a(PRE, a(PRE, v('x'))))
)
)))
l('r', ...)
围绕整个表达式。当使用 Y 组合器应用此函数时,
r
变量成为递归机制本身——
// Y combinator
// λf.(λx.f(x x))(λx.f(x x))
const Y = l('f', a(
l('x', a(v('f'), a(v('x'), v('x')))),
l('x', a(v('f'), a(v('x'), v('x'))))
))
toInt(a(Y, FIB, church(10))) // => 55
// expression constructors
const Variable = name =>
({ type: 'variable', name })
const Lambda = (parameter, body) =>
({ type: 'lambda', parameter, body })
const Apply = (procedure, argument) =>
({ type: 'application', procedure, argument})
const v = Variable
const l = Lambda
const a = (...exprs) => exprs.reduce(Apply)
// evaluator
const evaluate = (env, expr) => {
switch (expr.type) {
case 'variable':
return env[expr.name]()
case 'lambda':
return x =>
evaluate
( { ...env, [expr.parameter]: x }
, expr.body
)
case 'application':
return evaluate (env, expr.procedure) (_ => evaluate (env, expr.argument))
default:
throw Error(`unsupported expression: ${expr}`)
}
}
const toInt = expr =>
evaluate ({}, expr) (_ => x => x () + 1) (_ => 0)
const toBool = expr =>
evaluate ({}, expr) (_ => true) (_ => false)
// -----------------------------------------------------
// church encoding
const TRUE = l('a', l('b', v('a')))
const FALSE = l('a', l('b', v('b')))
const ISZERO = l('n', a(v('n'), l('x', FALSE), TRUE))
const NEXT =
l('n', l('f', l('x', a(v('f'), a(v('n'), v('f'), v('x'))))))
const PRE =
l('n', l('f', l('x', a(
v('n'),
l('g',l('h', a(v('h'), a(v('g'), v('f'))))),
l('u', v('x')),
l('u', v('u'))
))))
const ZERO = l('f', l('x', v('x')))
const PLUS = l('m', l('n', a(v('m'), NEXT, v('n'))))
const MINUS = l('m', l('n', a(v('n'), PRE, v('m'))))
const EXP = l('m', l('n', a(v('n'), v('m'))))
const MULT = l('m', l('n', l('f', a(v('m'), a(v('n'), v('f'))))))
const church = n => n === 0 ? ZERO : a(NEXT, church(n-1))
const IF = l('p', l('a', l('b', a(v('p'), v('a'), v('b')))))
const AND = l('p', l('q', a(v('p'), v('q'), v('p'))))
const OR = l('p', l('q', a(v('p'), v('p'), v('q'))))
const NOT = l('p', a(v('p'), FALSE, TRUE))
const LEQ = l('m', l('n', a(ISZERO, a(MINUS, v('m'), v('n')))))
const EQ = l('m', l('n', a(AND, a(LEQ, v('m'), v('n')), a(LEQ, v('n'), v('m')))))
const CONS = l('x', l('y', l('p', a(v('p'), v('x'), v('y')))))
const CAR = l('p',a(v('p'),l('x',l('y',v('x')))))
const CDR = l('p',a(v('p'),l('x',l('y',v('y')))))
const Y = l('g', a(
l('x', a(v('g'), a(v('x'), v('x')))),
l('x', a(v('g'), a(v('x'), v('x'))))
))
const FACT = l('r', l('n', a(
a(ISZERO, v('n')),
church(1),
a(MULT, v('n'), a(v('r'), a(PRE, v('n'))))
)))
const FIB =
l('r', l('x', a(
IF,
a(LEQ, v('x'), church(1)),
v('x'),
a(
PLUS,
a(v('r'), a(PRE, v('x'))),
a(v('r'), a(PRE, a(PRE, v('x'))))
)
)))
// tests
const assert = (label, actual, expected) =>
actual === expected
? console.log(label, "=>", actual)
: console.error(label, "=>", actual, `; expected: ${expected}`)
const assertTrue = (label, actual) =>
assert (label, actual, true)
const assertFalse = (label, actual) =>
assert (label, actual, false)
assert
( "IDENTITY #9"
, toInt(a(l('x', v('x')), church(9)))
, 9
)
assert
( "NEXT #7"
, toInt(a(NEXT, church(7)))
, 8
)
assertTrue
( "ISZERO #0"
, toBool(a(ISZERO, church(0)))
)
assertFalse
( "ISZERO #1"
, toBool(a(ISZERO, church(1)))
)
assertFalse
( "NOT TRUE"
, toBool(a(NOT, TRUE))
)
assertTrue
( "NOT FALSE"
, toBool(a(NOT, FALSE))
)
assertTrue
( "AND TRUE TRUE"
, toBool(a(AND, TRUE, TRUE))
)
assertFalse
( "AND TRUE FALSE"
, toBool(a(AND, TRUE, FALSE))
)
assertFalse
( "AND FALSE TRUE"
, toBool(a(AND, FALSE, TRUE))
)
assertFalse
( "AND FALSE FALSE"
, toBool(a(AND, FALSE, FALSE))
)
assertTrue
( "OR TRUE TRUE"
, toBool(a(OR, TRUE, TRUE))
)
assertTrue
( "OR TRUE FALSE"
, toBool(a(OR, TRUE, FALSE))
)
assertTrue
( "OR FALSE TRUE"
, toBool(a(OR, FALSE, TRUE))
)
assertFalse
( "OR FALSE FALSE"
, toBool(a(OR, FALSE, FALSE))
)
assert
( "IF TRUE #4 #5"
, toInt(a(IF, TRUE, church(4), church(5)))
, 4
)
assert
( "IF TRUE #4 #5"
, toInt(a(IF, FALSE, church(4), church(5)))
, 5
)
assert
( "IF (EQ #3 #3) #4 #5"
, toInt(a(IF, a(EQ, church(3), church(3)), church(4), church(5)))
, 4
)
assertTrue
( "LEQ #2 #4"
, toBool(a(LEQ, church(2), church(4)))
)
assertTrue
( "LEQ #4 #4"
, toBool(a(LEQ, church(4), church(4)))
)
assertFalse
( "LEQ #5 #4"
, toBool(a(LEQ, church(5), church(4)))
)
assertFalse
( "EQ #3 #4"
, toBool(a(EQ, church(3), church(4)))
)
assertTrue
( "EQ #4 #4"
, toBool(a(EQ, church(4), church(4)))
)
assertFalse
( "EQ #4 #5"
, toBool(a(EQ, church(4), church(5)))
)
assert
( "PLUS #4 #3"
, toInt(a(PLUS, church(4), church(3)))
, 7
)
assert
( "MINUS #9 #4"
, toInt(a(MINUS, church(9), church(4)))
, 5
)
assert
( "MULT #3 #5"
, toInt(a(MULT, church(3), church(5)))
, 15
)
assert
( "EXP #2 #5"
, toInt(a(EXP, church(2), church(5)))
, 32
)
assert
( "CAR (CONS #1 #2)"
, toInt(a(CAR, a(CONS, church(1), church(2))))
, 1
)
assert
( "CDR (CONS #1 #2)"
, toInt(a(CDR, a(CONS, church(1), church(2))))
, 2
)
assert
( "Y FACT #5"
, toInt(a(Y, FACT, church(5)))
, 120
)
assert
( "Y FIB #10"
, toInt(a(Y, FIB, church(10)))
, 55
)
IDENTITY #9 => 9
NEXT #7 => 8
ISZERO #0 => true
ISZERO #1 => false
NOT TRUE => false
NOT FALSE => true
AND TRUE TRUE => true
AND TRUE FALSE => false
AND FALSE TRUE => false
AND FALSE FALSE => false
OR TRUE TRUE => true
OR TRUE FALSE => true
OR FALSE TRUE => true
OR FALSE FALSE => false
IF TRUE #4 #5 => 4
IF TRUE #4 #5 => 5
IF (EQ #3 #3) #4 #5 => 4
LEQ #2 #4 => true
LEQ #4 #4 => true
LEQ #5 #4 => false
EQ #3 #4 => false
EQ #4 #4 => true
EQ #4 #5 => false
PLUS #4 #3 => 7
MINUS #9 #4 => 5
MULT #3 #5 => 15
EXP #2 #5 => 32
CAR (CONS #1 #2) => 1
CDR (CONS #1 #2) => 2
Y FACT #5 => 120
Y FIB #10 => 55
关于javascript - 在 Javascript 中使用 lambda 演算(使用教堂数字)的递归问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57453085/
(图1) 简单类型 lambda 演算的一部分(图 1),它在 Haskell 中实现,如下所示。 evaluate expression = do case expression
在 Tom Stuart 的《Understanding Computation》一书中,有一章专门介绍通过 Procs/Lambdas 重建 FizzBuzz。他首先讨论了如何通过过程定义数字,
在 lambda 演算中 (λ x. λ y. λ s. λ z. x s (y s z)) 用于添加两个 Church 数字,我们如何解释这一点,是否有用于函数式编程的 lambda 演算的任何好的
好的,所以我正在尝试实现 basics of lambda calculus .就到这里了。 我的号码: def zero[Z](s: Z => Z)(z: Z): Z = z def one[Z](
我一直在尝试在 C# 上实现原始 lambda 演算,但在实现它时遇到了一些麻烦,因为最后,我总是被要求提供对象。 例如,我想要一些可以让我定义一些基本逻辑组合子的东西,例如 I = Lambda x
我在 Haskell 编程中的冒险并不都是史诗般的。我正在实现简单的 Lambda 演算,我很高兴完成了语法、评估以及替换,希望它们是正确的。剩下的就是红色框中定义的打字(如下图所示),我正在寻找指导
如何扩展简单类型的 lambda 演算以拥有支持类似 monad 类型的类型系统?基本上,我目前对简单类型的 lambda 演算有了很好的理解,并且我想了解将 monad 添加到该基础的“最低要求”。
在 lambda 演算中,如果一个项具有范式,则正常的降阶策略将始终产生它。 我只是想知道如何严格证明上述命题? 最佳答案 您提到的结果是所谓的标准化定理的推论,指出对于任何归约序列 M->N,在相同
在 OCaml 中,“fun”似乎是我的绑定(bind)运算符。 OCaml 有内置替换吗?如果有,它是如何实现的?它是使用 de Bruijn 索引实现的吗? 只是想知道如何在 OCaml 中实现无
在 Haskell 中实现按值调用 lambda 演算时,我是否应该强制对对象语言中函数的参数求值(即按值调用 lambda 演算)来绕过调用 -元语言(即 Haskell)的按需求值顺序? 具体来说
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
为什么纯无类型 lambda 演算经常被描述为无法使用? 有了合适的函数库,它会不会与任何其他函数式语言大致相同? 最佳答案 速度不是大问题。例如,您可以决定使用教堂数字但优化实现,以便像往常一样表示
我正在将一些我在 python 中制作原型(prototype)的代码移植到闪存中,而 actionscript 并没有我预期的那么糟糕(我听说 v3 比 v2 好很多!)我还有一些东西这样做似乎过于
有人告诉我这个词 (z (λy.z x) (λy.y z)) 已经是正常形式了——但我不明白为什么。不能在这种状态下进行另一个 beta 缩减,并将术语 (λy.z x) 中所有出现的 y 替换为 (
Haskell 和 Lambda 演算中的 Python 代码是什么? def f1(): x = 77 def f2(): print x f2 f1 我在 lambd
我想用不同的编程语言实现 bool 值和 NOT 运算符的 lambda 演算构造。 它们是: TRUE = lx.ly. x FALSE = lx.ly. y NOT = lx. x FALSE T
使用 JavaScript。让我们定义以下内容: M = f => f(f) // Mocking Bird I = a => a // Identity 假设现在我们写这个表达式 M( f =>
我一直在玩 javascript(节点)中的 lambda 演算。 我创建了一些 Church 数字,并且一直在尝试创建一个计算斐波那契数列的递归函数,但它绝对行不通! 我曾尝试将函数包装在 Y 组合
我必须为 > 、 , != 编者注:我认为这就是 OP 试图提出的问题: 我正在尝试使用 Church 编码在无类型 lambda 演算中实现以下操作: 大于(GT 或 >)。 小于(LT 或 、
可以解释 Haskell 中的 lambda 演算: data Expr = Var String | Lam String Expr | App Expr Expr data Value a = V
我是一名优秀的程序员,十分优秀!