理解Scheme中Y组合器中的额外参数

时间:2017-12-17 03:12:54

标签: scheme y-combinator

根据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))

我的问题是关于hargs,它们没有出现在数学定义中,关于apply,它似乎应该是两半组合者或两者都没有。

有人可以帮我理解这里发生了什么吗?

1 个答案:

答案 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)做同样的事情。