January 10 2007 水曜日

  Yesterday evening I searched some articles on Y-combinator.  That is a so interesting and powerful combinator.
I think that what is the essence of Y-combinator is that it can make a call itself.  It has a parameter which is
just used to represent itself.  Are you puzzled?  OK. Let's look at its a implementation.

(define Y
  (lambda (x)
    ((lambda (maker)
       (x (lambda (arg) ((maker maker) arg))))
     (lambda (maker)
       (x (lambda (arg) ((maker maker) arg)))))))

  Here!

(lambda (maker)
  ...
  ((maker maker) ...))

  From above simplified code, what we can discover?  The code will trap into a infinite loop if running.  Yes,
very good.  Why there are two (lambda (maker) ...) in the body of "Y".  In actual fact, the two lambda express
is same to ((maker maker) ...), except that they are anonymous.  Their main task is to launch the infinite loop.
The first (lambda (maker) ...) is the former of the second; the second is the latter of the first.  Therefore,
the second will produce its latter by itself.  So, that is a infinite sequence.

  The (lambda (arg) ...) is also important.  Let's look at another example.

(define F*
  (lambda (func-arg)
    (lambda (n)
      (if (= n 0) 1
          (* n (func-arg (- n 1)))))))

((Y F*) 5) => 120

  The "F*" get a function as its argument.  So, (lambda (arg) ...) pass into the "F*".  In sense, the "F*" made
a fixpoint as its return value.  The "func-arg" represent a recursion (or loop) engine.

So, why we say that the Y-combinator is powerful?  It make us separate the code of a fixpoint and the code of
recursion when coding; it also combine they when running.

  Let's step into the ((Y F*) 5).  Firstly, let's discover what result (Y F*) make.  The "F*" is a lambda express.
So, (Y F*) is like the following code.

  ((lambda (maker)
       (F* (lambda (arg) ((maker maker) arg))))
   (lambda (maker)
       (F* (lambda (arg) ((maker maker) arg)))))

  Let's use "A" represent (lambda (maker) (F* (lambda (arg) ((maker maker) arg)))) for help our analysing.  All
right, we can get that code.

  ((lambda (maker)
       (F* (lambda (arg) ((A A) arg))))
   A))

  The simplified code, we found (A A) is embeded in a lambda express, (lambda (arg) ((A A) arg)).  At that point,
the infinite recursion is not produced at once.  Yes, it is delayed due to that lambda experss.  You can call up
how to implement a "delay" form.:-)  OK. Let's go on.

  Due to that lambda embracing (A A) the "F*" can get a lambda express as its argument.  It is time to get the "F*"
inside.  The "F*" also return a lambda express, which must be launched by giving a number.  So, the "F*" return a
lambda express like that.

(lambda (n)
      (if (= n 0) 1
          (* n ((lambda (arg) ((A A) arg) (- n 1)))))

  Let's go back the ((Y F*) 5).  It is same to the following code.

((lambda (n)
      (if (= n 0) 1
          (* n ((lambda (arg) ((A A) arg) (- n 1))))) 5)

  Evaluating this express will result in a recursion because the "n" is 5.  So, it cause that.

(* 5 ((lambda (arg) ((A A) arg) (- 5 1)))))

((A A) 4)

  The (A A) result in (F* (lambda (arg) ((A A) arg))) again.  So, we can know the followning code.

(* 4 ((lambda (arg) ((A A) arg) (- 4 1)))))

  Again ang again.  Before launching the next recursion, the fixpoint function test whether the "n"
is 0, if true stop recursion and return 1; otherwise, it have to launch a recursive call again.

  It result in a recursive calling chain, which just find its fixpoint.  Returning from the fixpoint,
it actually work out the result of factoral.

  OK.  Now we can write a function in Y-combinator to find a maximum from a list of number.

(define M*
  (lambda (f)
    (lambda (ls)
      (if (null? (cdr ls)) (car ls)
          (max (car ls) (f (cdr ls))))))) 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值