我无法理解的Y组合子,所以我想实现一个启用递归没有本地实现的功能。 经过一番思考,我结束了这一点:
Y = λx.(λv.(x x) v)
这是比实际更短:
Y = λf.(λx.f (x x)) (λx.f (x x))
而且,对于我吃惊的是,工作。 一些例子:
// JavaScript
Y = function(x){
return function(v){
return x(x, v);
};
};
sum = Y(function(f, n){
return n == 0 ? 0 : n + f(f, n - 1);
});
sum(4);
; Scheme
(define Y (lambda (x) (lambda (v) (x x v))))
(define sum (Y
(lambda (f n)
(if (equal? n 0)
0
(+ n (f f (- n 1)))))))
(sum 4)
两个片段输出10(求和从0到4)如预期。
这是什么,为什么它是短,为什么我们喜欢更长的版本?
它之所以是较短的是,你实现什么不 Y组合。 这件事情,是实际的Y组合,以及东西有时被称为U形组合子之间。 要成为一个适当的Y组合,这应该工作:
(define sum
(Y (lambda (f)
(lambda (v) (if (equal? n 0) 0 (+ n (f (- n 1))))))))
或在Javascript:
sum = Y( function(f) { return function(n) {
return n == 0 ? 0 : n + f(n-1);
};});
如果你用自己的方式工作,这是令的工作,你会发现一两件事,这将使它不再是你需要移动复制f
东西进入Y,这使得接下来的事情它甚至更长的时间是当你最终保护xx
自应用程序的功能里面,因为这些语言都是严格。
从“真正的”版本不同的是,你需要通过自己的函数中的参数,你通常不需要沿 - Y上给你的函数本身的recursice变种做了抽象。
点心在JavaScript中应该是公正
Y (function(rec){ return function (n) { return n==0 ? 0 : n + rec(n-1); };})
我明白了Y组合时我重组了共同JS表达至
function Y (f) {
function alt (x) {
function rec (y) { // this function is basically equal to Y (f)
return x(x)(y); // as x === alt
}
return f (rec);
}
return alt(alt);
}
文章来源: I couldn't understand the Y-Combinator, so I tried to implement it and ended up with something shorter, which worked. How is that possible?