Y Combinator

常见的例子

阶乘函数:

fact = (a) -> if a > 0 then a * fact(a - 1) else 1

问题的提出

如上,在fact函数中调用了fact本身,无法使用匿名函数表达,如何解决这一问题?

初步的尝试

初始的f:

f = (a) -> if a > 0 then a * f(a - 1) else 1

第一步,去除自身的递归调用:

f1 = (a) -> if a > 0 then a * f(a - 1) else 1

第二步,f1调用了f,将f提出,使得f'只依赖于输入:

f' = (f) -> (a) -> if a > 0 then a * f(a - 1) else 1

第三步,将f代入:

f' f = f

数学中,f(x)=x,此时x为f(x)的不动点;

同样的,f'(f)=f,此时f为f'的不动点。

此时,f(x)=f'(f(x)),接下来就是求f'。

进一步探索

当前的问题:求f'

令f=Y f',求解f与f'之间的关系。

这时有:

f = Y f'

进而有:

f = f' f = Y f' = f' Y f'

得出:

Y = f -> f Y f

故而我们需要求出Y组合子(Y Combinator)。

Y组合子

现成的Y组合子:

Y = f -> (x -> f x x) (x -> f x x)

证明:

Y g = (x -> g x x) (x -> g x x)

      = (x -> g x x) (x -> g x x)

      = g (x -> g x x) (x -> g x x)

      = g Y g

其他组合子:

Z = f -> (x -> f (y -> x x y)) (x -> f (y -> x x y))

Y' = (x -> y -> x y x) (y -> x -> y x y x)

Θ = (x -> y -> y x x y) (x -> y -> y x x y)

问题的解决

对阶乘函数fact:

fact = (f) -> (a) -> if a > 0 then a * f(a - 1) else 1

有:

Y fact = fact Y fact

          = (a) -> if a > 0 then a * (Y fact)(a - 1) else 1

这样,Y fact实现了和阶乘函数一样的功能。

可以写出:

fact = ((f) -> ((x) -> (n) -> (f x x)(n)) ((x) -> (n) -> (f x x)(n))) (f) -> (a) -> if a > 0 then a * f(a - 1) else 1

JS调用fact(5):

(function(f) {
    return (function(h) {
        return h(h)
    })(function(x) {
        return function(n) {
            return f(x(x))(n)
        }
    })
})(function(f) {
    return function(n) {
        return n > 0 ? n * f(n - 1) : 1
    }
})(5)

总结

综上可知,匿名函数可写成Y(f),f的类型为f->TInput->TResult,则Y的类型为(f->TInput->TResult)->TInput->TResult

原文地址:https://www.cnblogs.com/bajdcc/p/5757410.html