Applicative Order vs. Normal Order Evaluation

(define (square x) (* x x))
(define (sum-of-squares x y) (+ (square x) (square y)))
(define (f x) (sum-of-squares x (+ x 1)))

In Applicative Order Evaluation arguments to functions get evaluated (reduced as much as possible) before being passed to a function. Here’s a trace of what would happen do a function call f defined above with arguments of 3 and (+ 3 1).

(f 3)
(sum-of-squares 3 (+ 3 1))
(sum-of-squares 3 4)
(+ (square 3) (square 4))
(+ (* 3 3) (* 4 4))
(+ 9 16)
25

In Normal Order Evaluation a full expansion of all the function application happens first and then the arguments are evaluated.

(f 3)
(sum-of-squares 3 (+ 3 1))
(+ (square 3) (square (+ 3 1))
(+ (* 3 3) (* (+ 3 1) (+ 3 1)))
(+ 9 (* 4 4))
(+ 9 16)
25

The best case and simplest case I can think of illustrating the difference between the two is the following: Suppose there is a defined function rand which will return a random integer, (rand 100) returns an random int between 0 and 100. In this case I pretend that (rand 100) returned 13.

Applicative Evaluation

(f (rand 100))
(sum-of-squares 13)
(sum-of-squares 13 (+ 13 1))
(sum-of-squares 13 14)
(+ (square 13) (square 14))
(+ (* 13 13) (* 14 14))
(+ 169 196)
365

The chances of running (f (rand 100)) under applicative order again and getting the same answer is 1/100.

Normal Order Evaluation

(f (rand 100))
(sum-of-squares (rand 100) (+ (rand 100) 1))
(+ (square (rand 100)) (square (+ (rand 100) 1))
(+ (* (rand 100) (rand 100)) (* (+ (rand 100) 1) (+ (rand 100) 1)))

I want to stop here to note that all 4 calls to (rand 100) should, if the rand function is any good, evaluate to 4 random integers between 0 and 100. Only if there is a lot of luck involved (the chances of the this Normal Order f being the same its Applicative Order cousin is about 1 in one hundred million) will the rest of this statement evaluate to the same result as the the Applicative Evaluation earlier.