For the next step, let's examine how to separate further the management of h in our factorial function from the management of n. Recall that the factorial program looks like:
(let ((g (lambda (h) (lambda (n) (if (< n 2) 1 (* n ((h h ) (- n 1))) )))))) ((g g) 10))
Our plan of attack is to abstract the if expression over (h h) and n, which will accomplish two things: the resulting function will become independent of its surrounding bindings and the management of the control argument will become separated from the numeric argument. The result of the abstraction is:
(let ((g (lambda (h) (lambda (n) (let ((f (lambda (q n) (if (< n 2) 1 (* n (q (- n 1))))))) (f (h h) n)))))) ((g g) 10))
We can curry the definition of f, which also changes its call:
(let ((g (lambda (h) (lambda (n) (let ((f (lambda (q) (lambda (n) (if (< n 2) 1 (* n (q (- n 1)))))))) ((f (h h)) n)))))) ((g g) 10))
Notice that the definition of the function f need not be deeply embedded in the function g. Therefore, we can extract the main part of the function -- the part that computes factorial -- from the rest of the code.
(let ((f (lambda (q) (lambda (n) (if (< n 2) 1 (* n (q (- n 1)))))))) (let ((g (lambda (h) (lambda (n) ((f (h h)) n))))) ((g g) 10)))
The form of f is once again the parameterized form of factorial, and we can abstract this expression over f, which produces Y as follows:
(define Y (lambda (f) (let ((g (lambda (h) (lambda (x) ((f (h h)) x)) ))) (g g))))
This is one way to derive Y.