I have this code knowing that parameters are passed using call by need:
(define fact-2
(let ((foo (lambda (n f)
(if (zero? n)
1
(f n f)))))
(lambda (n)
(let ((res 1))
(foo n (begin
(set! res (* res n))
(set! n (- n 1))
foo))
res))))
I feel like I am missing something, but in the call by need calling foo with this object as f, it will calculate f once and then will never update res and n. Is this correct? Am I missing something?
Thank you.
You are correct. Only with call-by-name the
beginexpression will get evaluated on each call tof(except for the very first time) -- to find out what it is that we're calling, only if the call tofis indeed made.With call-by-value the
beginexpression will be evaluated only once, before the very first call tofoo.With call-by-need it might get evaluated at most once, when and if at the end of the very first call to
foothere's a need to callfagain.Let's look at how a call-by-name version could be simulated in the regular call-by-value Scheme:
Calling
(fact2 5)produces120in Racket.For call-by-value semantics your code needs no changes (to be interpreted in the regular call-by-value Scheme) and will of course loop, for the
(fact-2 5)call (and indeed does so, in Racket).And under the call-by-need semantics each lambda's body (of the two new lambda wrappers) will be evaluated only for the very first time it is called, whereupon it will save the calculated value and then return it; and for all the subsequent calls the saved value will be immediately returned, without evaluating the body. Thus the
set!forms will be evaluated at most once, and the code, with the example test call(fact-2 5)will, again, loop.