4.5 Exercise 4.5

The most natural place to add support for the alternate form is in expand-clauses. In the alternate case, we reformulate the generated code to be an if expression wrapped in an immediately-invoked lambda (since we won’t have let expansion until the next exercise), so we can reuse the computed value if it turns out to be truthy.

(define (expand-clauses clauses)
  (if (null? clauses)
      'false
      (let ((first (car clauses))
            (rest (cdr clauses)))
        (cond ((cond-else-clause? first)
               (cond ((cond-alternate-form? first)
                      (error "ELSE clause isn't allowed in alternate form" clauses))
                     ((null? rest) (sequence->exp (cond-actions first)))
                     (else (error "ELSE clause isn't last -- COND->IF" clauses))))
              ((cond-alternate-form? first)
               (let ((rest-expanded (expand-clauses rest)))
                 (list (make-lambda '(v f) (list (make-if 'v '(f v) rest-expanded)))
                       (cond-predicate first)
                       (cond-alternate-form-proc first))))
              (else
               (let ((rest-expanded (expand-clauses rest)))
                 (make-if (cond-predicate first)
                          (sequence->exp (cond-actions first))
                          rest-expanded)))))))

We also rely on the following helper procedures:

(define (cond-alternate-form? clause)
  (eq? (car (cond-actions clause)) '=>))
(define (cond-alternate-form-proc clause) (cadr (cond-actions clause)))