4.4 Exercise 4.4

or and and can be implemented by direct evaluation in the interpreter as follows:

(define (eval-and exps env)
  (define (iter rest)
    (cond ((null? rest) true)
          (((car rest)) (iter (cdr rest)))
          (else false)))
  (iter (map (lambda (exp) (lambda () (eval exp env))) exps)))
(define (eval-or exps env)
  (define (iter rest)
    (cond ((null? rest) false)
          (((car rest) true))
          (else (iter (cdr rest)))))
  (iter (map (lambda (exp) (lambda () (eval exp env))) exps)))

Here, we follow the same pattern of creating a thunk evaluating to the eval’d form of each expression (wrapped in a thunk in order to simulate the lazy evaluation of the arguments to these special forms) and iterating through them as much as is necessary to find the answer.

Alternatively, we could translate each of them into a set of nested if expressions:

(define (expand-and exps)
  (if (null? exps)
      true
      (make-if (car exps) (expand-and (cdr exps)) 'false)))
(define (expand-or exps)
  (if (null? exps)
      false
      (make-if (car exps) 'true (expand-or (cdr exps)))))

Here, expand-and and expand-or are procedures which return syntactic objects that will evaluate to the correct result. The way that this can work is by passing the first expression as the predicate to if, and either resulting in a constant value if we know the answer or an expression computing the answer given the rest of the expressions if we don’t. The latter can be accomplished by recursively calling the expansion procedure.