根据RosettaCode,Scheme中的Y Combinator实现为
(define Y
(λ (h)
((λ (x) (x x))
(λ (g)
(h (λ args (apply (g g) args)))))))
当然,传统的Y Combinator是λf。(λx.f(x x))(λx.f(x x))
我的问题是关于h
和args
,它们没有出现在数学定义中,关于apply
,它似乎应该是两半组合者或两者都没有。
有人可以帮我理解这里发生了什么吗?
答案 0 :(得分:1)
让我们开始将lambda演算版本转换为Scheme:
(λ (f)
((λ (x) (f (x x)))
(λ (x) (f (x x)))))
我想简化这一点,因为我看到(λ (x) (f x x))
重复了两次。你可以用那里的开头替换它:
(λ (f)
((λ (b) (b b))
(λ (x) (f (x x)))))
Scheme是一种急切的语言,因此它将进入无限循环。为了避免我们创建代理..假设您有+
需要两个数字,您可以用(λ (a b) (+ a b))
替换它而不会更改结果。让我们用代码来做:
(λ (f)
((λ (b) (b b))
(λ (x) (f (λ (p) ((x x) p))))))
实际上这有自己的名字。它被称为Z组合子。仅在应用提供的代理时应用(x x)
时才会执行f
。延迟一步。它可能看起来很奇怪,但我知道(x x)
成为一个函数,所以这与我上面的+
替换完全相同。
在Lambda演算中,所有函数都有一个参数。如果您看到f x y
它与Scheme中的((f x) y)
实际上相同。如果您希望它与所有arities的功能一起使用,您的替换需要反映出来。在Scheme中,我们有休息参数和apply
来执行此操作。
(λ (f)
((λ (b) (b b))
(λ (x) (f (λ p (apply (x x) p))))))
如果您只打算使用lambda演算中的一个arity函数,那么这不是必须的。
请注意,在您的代码中,您使用的是h
而不是f
。你称之为变量并不重要。这是具有不同名称的相同代码。所以这是一样的:
(λ (rec-fun)
((λ (yfun) (yfun yfun))
(λ (self) (rec-fun (λ args (apply (self self) args))))))
毋庸置疑(yfun yfun)
和(self self)
做同样的事情。