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 thelet
expression).
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)
.