Call by name is actually a closure based mechanism under the hood. It's like lazy evaluation, but with side effects allowed:
(let ((0 42))
(a #(1 2 3))
(foo (aref a (incf i))))
If foo is call by name, then it receives a thunk (basically a lexical closure) for the argument. The aref expression is then evaluated inside foo whenever foo refers to the corresponding argument. (Unfortunately, repeating the incf side effect).
We could simulate this with:
(foo (lambda () (aref a (incf i)))
with foo using (funcall arg) to get the argument's value.
Call by need, described below that, seems exactly like the insertion of delay and force. The call-by-need argument expression is basically wrapped in an implicit delay, and callee refers to the argument value using implicit force. delay and force are just additional wrapping around a closure to add a flag to squash multiple evaluations.
Call by name is actually a closure based mechanism under the hood. It's like lazy evaluation, but with side effects allowed:
If foo is call by name, then it receives a thunk (basically a lexical closure) for the argument. The aref expression is then evaluated inside foo whenever foo refers to the corresponding argument. (Unfortunately, repeating the incf side effect). We could simulate this with: with foo using (funcall arg) to get the argument's value.Call by need, described below that, seems exactly like the insertion of delay and force. The call-by-need argument expression is basically wrapped in an implicit delay, and callee refers to the argument value using implicit force. delay and force are just additional wrapping around a closure to add a flag to squash multiple evaluations.