非递归lambda演算阶乘函数

非递归lambda演算阶乘函数,lambda,functional-programming,lambda-calculus,Lambda,Functional Programming,Lambda Calculus,如何使用lambda演算编写阶乘函数而不使用递归?仅表示数学符号,而不是在任何特定编程语言中的实现 我什么都没说我不是故意的 “不使用递归”的意思必须是“不使用名称调用自身的函数” 不管怎样,让我们写阶乘 fact := λn. zero? n one (mult n (fact (dec n))) 要做到这一点,最简单的方法是将lambda应用于自身–满足U组合符 现在,我们可以将原始表达式包装在lambda中,并应用U fact := U (λf. λn. zero? n one (mult

如何使用lambda演算编写阶乘函数而不使用递归?仅表示数学符号,而不是在任何特定编程语言中的实现

我什么都没说我不是故意的

“不使用递归”的意思必须是“不使用名称调用自身的函数”

不管怎样,让我们写阶乘

fact := λn. zero? n one (mult n (fact (dec n)))
要做到这一点,最简单的方法是将lambda应用于自身–满足U组合符

现在,我们可以将原始表达式包装在lambda中,并应用
U

fact := U (λf. λn. zero? n one (mult n (??? (dec n))))
是的,是的,但更精明的人会注意到,你也可以直接在lambda内部使用镜子(U)

fact := U (λf. λn. zero? n one (mult n (U f (dec n))))

有效吗?

表示为#N的所有教堂数字

如果说“不使用递归”,你的意思是不使用一般的递归和 因此,如果没有不动点(或自应用程序),我们可以简单地观察到阶乘函数是本原递归的(即,本质上是迭代的),并且通过迭代(由church数字提供)和成对对本原递归进行非常一般和简单的编码。 我将讨论一个很有启发性的一般情况。 设是对的一些编码,并设fst和snd是相关联的 预测。例如,您可以定义

<M,N> = λz. z M N
fst = λp. p (λxy.x)
snd = λp. p (λxy.y)
其中a和h已经定义

一般的想法是使用辅助函数f',其中

                       f'(x) = <x,f(x)>
f'(x)=
因此,f'(0)=<0,a>,并且给定对p==f'(x),我们构建 下一对通过计算第一个分量上的后继项 将h应用于这对参数(即,利用 对对进行编码,相当于将连续h作为输入传递给对p)

综上所述,

next = λp.< succ (fst p), p h>
next=λp.
最后,为了计算f(n),我们需要对下一个函数进行n次迭代 从<0,a>开始,然后取第二个分量:

 f = λn. snd (n next <0,a>)
f=λn。snd(n下一个)

从N开始乘以N*--N直到N为1的循环?当你说“不使用递归”时,你的意思是“不使用不动点组合器”?如果是这样,那是不可能的。@GradyPlayer lambda演算只由函数组成。没有循环。你有序列符号吗?@GradyPlayer没有,你有lambda、应用程序和变量
U f=f
不会在Haskell中进行打字检查。@AaditMShah谢谢–我没有花时间在ghci中测试它;只是从来没有见过Y那样^ ^我更喜欢定义
yf=f(yf)
,因为你可以看到递归自然展开,也可以看到行动中的惰性,防止无限循环。也=确实如此,但该定义需要现有的递归功能;从添加不存在的功能的角度来看,这会降低它的趣味性–感谢分享链接;以前从未听说过他,但是在类型良好的语言中,如果没有固定点原语,就无法定义固定点组合符,因为递归依赖于(即
U f=f
)。但是,这样的表达式不会进行类型检查。至少对我来说不是。在一个无关的注释中,您的表达式
U。(.U)
也不会进行类型检查。使用church数字来驱动迭代是一个更好的答案,因为这样做没有递归的影响–非常好的回答谢谢。Gerard Huet在30多年前向我解释了这项技术,但我不确定谁应该为此负责。也许有人知道答案。使用内置在教堂数字中的迭代更直接的方法是λn.λf.n(λf.λn.n(f(λf.λx.n f(f x)))(λx.f)(λx.x)(由于Bertram Felgenhauer),如图所示,
fact := (λf. λn. zero? n one (mult n (f f (dec n)))) (λf. λn. zero? n one (mult n (f f (dec n))))
fact := U λf. λn. zero? n #1 (mult n (U f (dec n)))

fact #4

U (λf. λn. zero? n #1 (mult n (U f (dec n))) #4

(λf. f f) (λf. λn. zero? n #1 (mult n (U f (dec n))) #4

(λf. λn. zero? n #1 (mult n (U f (dec n))) (λf. λn. zero? n #1 (mult n (U f (dec n))) #4

(λn. zero? n #1 (mult n (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec n))) #4

zero? #4 #1 (mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))

zero? #4 #1 (mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))

// (zero? #4); false; returns second argument
(mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))

// which is #4 * ...
(U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4))

// which is ...
(U (λf. λn. zero? n #1 (mult n (U f (dec n))) #3)

// which is equivalent to...
fact #3

// so ...
(mult #4 (fact #3))

// repeating this pattern ...
(mult #4 (mult #3 (fact #2))
(mult #4 (mult #3 (mult #2 (fact #1)))
(mult #4 (mult #3 (mult #2 (mult #1 (fact #0))))
(mult #4 (mult #3 (mult #2 (mult #1 #1))))
(mult #4 (mult #3 (mult #2 #1)))
(mult #4 (mult #3 #2))
(mult #4 #6)
#24
<M,N> = λz. z M N
fst = λp. p (λxy.x)
snd = λp. p (λxy.y)
f(0) = a
f(x+1) = h(x,f(x))
                       f'(x) = <x,f(x)>
next = λp.< succ (fst p), p h>
 f = λn. snd (n next <0,a>)