I am currently, going through this article on Y-combinator by Mike Vanier.
Along the way of Y-combinator derivation, this code:
(define (part-factorial self)
  (lambda (n)
    (if (= n 0)
      1
      (* n ((self self) (- n 1))))))
((part-factorial part-factorial) 5) ==> 120
(define factorial (part-factorial part-factorial))
(factorial 5) ==> 120
is worked out to:
(define (part-factorial self)
  (let ((f (self self)))
    (lambda (n)
      (if (= n 0)
        1
        (* n (f (- n 1)))))))
(define factorial (part-factorial part-factorial))
(factorial 5) ==> 120
After that, article states:
This will work fine in a lazy language. In a strict language, the
(self self)call in the let statement will send us into an infinite loop, because in order to calculate(part-factorial part-factorial)(in the definition of factorial) you will first have to calculate (part-factorial part-factorial) (in theletexpression).
and then reader is challenged:
For fun: figure out why this wasn't a problem with the previous definition.
It seems to me I've figured out why, though I would like to confirm that:
- I am correct in my understanding.
- I don't miss any critical points, in my understanding.
My understanding is: in the first code snippet (self self) call won't result into infinite loop, because it is contained (wrapped) into lambda as a part-factorial function, and thus evaluated to lambda (n) until the call to (self self) is actually made, which happens only for n > 0. Thus, after (= n 0) evaluates to #t, there is no need in calling (self self).
