Y combinator in javascript

本文借助阶乘函数,在javascript中推导了Y combinator。


原始的阶乘函数定义

var fact=function(n){

    return n==0?1:n*fact(n-1);

};


console.assert(fact(5)==120);


把递归函数作为参数传递

var highFact=function(f){

    return function(n){

        return n==0?1:n*f(f)(n-1);

    };

};


console.assert(highFact(highFact)(5)==120);


借助辅助函数消除对自身的调用

var fact=(function(g){

    return g(g);

}(function(f){

    return function(n){

        return n==0?1:n*f(f)(n-1);

    };

}));


console.assert(fact(5)==120);


构造递归原型

var fact=(function(g){

    return g(g);

}(function(f){

    return function(n){

        var factProto=function(h){

            return function(x){

                return x==0?1:x*h(x-1);

            };

        };

        return factProto(f(f))(n);

    };

}));


console.assert(fact(5)==120);


将递归原型提取出来

var factProto=function(h){

    return function(x){

        return x==0?1:x*h(x-1);

    };

};


var fact=(function(g){

    return g(g);

}(function(f){

    return function(n){

        return factProto(f(f))(n);

    };

}));


console.assert(fact(5)==120);


把递归原型变成形参

var fact=(function(k){

    return (function(g){

        return g(g);

    }(function(f){

        return function(n){

            return k(f(f))(n);

        };

    }));

}(factProto));


console.assert(fact(5)==120);


得到Y combinator

var yCombinator=function(k){

    return (function(g){

        return g(g);

    }(function(f){

        return function(n){

            return k(f(f))(n);

        };

    }));

};


console.assert(yCombinator(factProto)(5)==120);


扩展为多参数形式

var yCombinator=function(k){

    return (function(g){

        return g(g);

    }(function(f){

        return function(){

            return k(f(f)).apply(null,arguments);

        };

    }));

};


console.assert(yCombinator(factProto)(5)==120);