In Scheme, I modified the basic 'if' command as:
(define (modified-if predicate then-clause else-clause)
(if predicate
then-clause
else-clause))
And then I defined a simple factorial generating program using the modified version of if:
(define (factorial n)
(modified-if (= n 0)
(* n (factorial (- n 1)))))
Now, when I call the above function, it goes into an infinite loop. Why does that happen?
Scheme has eager evaluation. This means that, unless you're using a special form (like if
) or a macro (like cond
or case
) that delegates to such a special form, all subexpressions are evaluated first.
That means for your expression
(modified-if (= n 0)
1
(* n (factorial (- n 1))))
the (* n (factorial (- n 1)))
is evaluated first, before modified-if
is run. (It may be run before or after (= n 0)
, but it doesn't matter either way, the recursive call still happens regardless.) And since this is a recursive call, that means that your program will infinitely recurse, and you will eventually run out of stack.
Here's a simple example: consider this:
(if #t
(display "Yay!")
(error "Oh noes!"))
Because if
is a special form, and it only evaluates the necessary branch, in this case it will only evaluate (display "Yay!")
and not evaluate (error "Oh noes!")
. But if you switch to using your modified-if
, both expressions will be evaluated, and your program will raise an error.
Use the stepper in DrRacket to see how your modified-if behaves.
Choose the "Beginner" language. Enter the program below, and then click the stepper icon:
(define (modif predicate then-clause else-clause)
(if predicate then-clause else-clause))
(define (factorial n)
(modif (= n 0) 1 (* n (factorial (- n 1)))))
(factorial 5)
You can now step for step see how the computation evolves. Notice that modif
follows the rule of function application.
For an example of how the DrRacket stepper looks like: