美文网首页
Y combinator 推导过程

Y combinator 推导过程

作者: 风干鸡 | 来源:发表于2016-10-29 18:55 被阅读0次

    首先需要一个递归的函数

    以阶乘为例
    函数名为factorial,参数为n。如果n = 0返回1,否则返回factorial(n - 1)

    定义一个辅助函数zero?,判断n是否等于0

    (define (zero? n)
      (= n 0))
    

    过程定义:

    (define (factorial n)
      (if (zero? n)
          1
          (* n (factorial (- n 1)))))
    

    换一种形式:

    (define factorial
      (lambda (n)
        (if (zero? n)
            1
            (* n (factorial (- n 1))))))
    

    消除函数名

    Y combinator 目的就是消除递归中函数的名字。为了消除他,递归部分的函数名改为从参数中获取,也就是如下形式:

      (lambda (f)
        (lambda (n)
          (if (zero? n)
              1
              (* n (f (- n 1)))))))
    

    那么我们要写的函数应用到自身返回目标函数,如下:

    (define fact-factory
      (lambda (f)
        (lambda (n)
          (if (zero? n)
              1
              (* n ((f (- n 1)))))))
    
    ((fact-factory fact-factory) 5)
    

    不能运行,因为参数fact-factory是的参数是函数类型,而n - 1是数字类型。将f改为(f f)

    (define fact-factory
      (lambda (f)
        (lambda (n)
          (if (zero? n)
              1
              (* n ((f f) (- n 1)))))))
    
    ((fact-factory fact-factory) 5)
    
    120
    

    去掉函数名,就是如下形式:

    (((lambda (f)
        (lambda (n)
          (if (zero? n)
              1
              (* n ((f f) (- n 1))))))
     (lambda (f)
        (lambda (n)
          (if (zero? n)
              1
              (* n ((f f) (- n 1))))))) 5)
    

    推广

    现在要做的就是把函数的定义和生成他的部分分离,函数定义作为一个参数传进去。

    变换成如下形式:

    (lambda (fun)
      (lambda (n)
        (if (zero? n)
            1
            (* n (fun (- n 1))))))
    

    (f f)作为参数,该表达式的值就是最终的目标函数。

    (lambda (n)
      ((fun-factory fun-factory) n))
    

    fun-factory从参数获取,综合:

      (lambda (fun-factory)
        ((lambda (fun)
           (lambda (n)
             (if (zero? n)
                 1
                 (* n (fun (- n 1))))))
         (lambda (n)
           ((fun-factory fun-factory) n))))
    

    把该函数应用到自身就可以得到目标函数了,并且定义部分完全独立。

    那么我们在外面再套一层,定义部分作为参数。最终形式:

    ((lambda (fun-definition)
       ((lambda (fun-factory)
          (fun-definition (lambda (n) ((fun-factory fun-factory) n))))
        (lambda (fun-factory)
          (fun-definition (lambda (n) ((fun-factory fun-factory) n))))))
     (lambda (fun)
        (lambda (n)
          (if (zero? n)
              1
              (* n (fun (- n 1)))))))
    

    代入参数正确运行。

    其中的前半部分就是Y combinator,后半部分为函数定义。我们把他命名,留到后面使用。

    (define Y
      (lambda (X)
        ((lambda (procedure)
           (X (lambda (arg) ((procedure procedure) arg))))
         (lambda (procedure)
           (X (lambda (arg) ((procedure procedure) arg)))))))
    

    所以递归函数的只要写成如下形式,便可以完全消除函数名。

    (lambda (fun)
      (lambda (args)
        (fun (abc))))
    

    比如斐波那契数列就可以写成

      (lambda (fun)
        (lambda (n)
          (cond ((= n 0) 0)
                ((= n 1) 1)
                (else
                 (+ (fun (- n 1)) (fun (- n 2)))))))
    

    传入Y combinator

    ((Y
      (lambda (fun)
        (lambda (n)
          (cond ((= n 0) 0)
                ((= n 1) 1)
                (else
                 (+ (fun (- n 1)) (fun (- n 2)))))))) 10)
    
    55
    

    附一个Java的Y combinator

        interface RecurFunc<T> extends Function<RecurFunc<T>, T> {}
    
        public static <T, R> Function<T, R> y(Function<Function<T, R>, Function<T, R>> x) {
            RecurFunc<Function<T, R>> prod = f -> x.apply(arg -> f.apply(f).apply(arg));
            return prod.apply(prod);
        }
    
        public static void main(String[] args) {
            Function<Integer, Integer> fact = y(f -> n -> n == 1 ? 1 : n * f.apply(n - 1));
            System.out.println(fact.apply(5));
        }
    

    完。

    http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html

    相关文章

      网友评论

          本文标题:Y combinator 推导过程

          本文链接:https://www.haomeiwen.com/subject/boeyuttx.html