Alyssa P. Hacker doesn’t see why
if needs to be provided as a special form. “Why can’t I just define it as an ordinary procedure in terms of
cond” she asks. Alyssa’s friend Eva Lu Ator claims this can indeed be done, and she defines a new version of
Eva demonstrates the program for Alyssa:
Delighted, Alyssa uses
new-if to rewrite the square-root program:
What happens when Alyssa attempts to use this to compute square roots? Explain.
new-if appears to work since in the simple example we’re getting the correct results. However, the applicative order of evaluation of the
new-if is a subtle but important difference compared to the actual
With applicative order evaluation of function applications, both the then-clause and the else-clause gets executed. We’re going to end up always evaluating
sqrt-iter even if the guess is good enough. This completely breaks recursive procedures that rely on the satisfaction of base case conditions to terminate calls. In this case, the recursive calls will never end because
sqrt-iter will be called all the time.
I really like this exercise because at a glance, it seems perfectly reasonable to implement
if in terms of
cond – I mean, they both exhibit the evaluation style that you want.
else clauses won’t be executed at all if the predicate is true. So why not just substitute one for the other?! That sounds good! But in trying to do this by defining a new function, you immediately lose the special-case evaluation behavior 😹. This really further drives home the essential nature of lazy evaluation behavior for conditionals.
I think often as consumers of programming languages we take this behavior for granted and don’t think twice about how conditional expressions are evaluated. But this sort of exercise (and many exercises in SICP!) puts you in the seat of the language designer.