sicp-ex-4.5



<< Previous exercise (4.4) | Index | Next exercise (4.6) >>


meteorgan

  
  
 (define (extended-cond-syntax? clause) (eq? (cadr clause) '=>)) 
 (define (extended-cond-test clause) (car clause)) 
 (define (extended-cond-recipient clause) (caddr clause)) 
 (define (cond->if expr) 
         (expand-clauses (cond-clauses expr))) 
 ;; convert cond expression to if expression 
 (define (expand-clauses clauses) 
         (if (null? clauses) 
                 'false 
                 (let ((first (car clauses)) 
                           (rest (cdr clauses))) 
                         (cond ((cond-else-clause? first) 
                                    (if (null? rest) 
                                            (sequence->exp (cond-actions first)) 
                                            (error "ELSE clause isn't last -- COND->IF" clauses))) 
                                   ((extended-cond-syntax? first) 
                                    (make-if (extended-cond-test first) 
                                                         (list (extended-cond-recipient first) 
                                                                   (extended-cond-test first)) 
                                                         (expand-clauses rest))) 
                                 (else  
                                         (make-if (cond-predicate first) 
                                                      (sequence->exp (cond-actions first)) 
                                                      (expand-clauses rest))))))) 

bagratte

  
  
  
 (define (expand-clauses clauses) 
   (if (null? clauses) 
       'false                          ; no else clause 
       (let ((first (car clauses)) 
             (rest (cdr clauses))) 
         (if (cond-else-clause? first) 
             (if (null? rest) 
                 (sequence->exp (cond-actions first)) 
                 (error "ELSE clause isn't last -- COND->IF" 
                        clauses)) 
             (let ((test (cond-predicate first)) 
                   (recepient (if (eq? (car (cond-actions first)) '=>) 
                                  (cadr (cond-actions first)) 
                                  false))) 
               (make-if test 
                        (if recepient 
                            (list recepient test) ;test-recepient cond 
                            (sequence->exp (cond-actions first))) ;normal cond 
                        (expand-clauses rest))))))) 

leafac

Both solutions above fail to consider that evaluating the condition twice (once to check for truthiness, then again to pass the value as parameter to the lambda) may have undesired consequences on the presence of side-effects. Suppose the clause is

 (begin (set! x (+ x 1)) x) 

for example.

The solution is to use lambdas that are immediately applied to encode `let' bindings:

 (define (expand-clauses clauses) 
   (if (null? clauses) 
       'false                          ; no else clause 
       (let ((first (car clauses)) 
             (rest (cdr clauses))) 
         (if (cond-else-clause? first) 
             (if (null? rest) 
                 (sequence->exp (cond-actions first)) 
                 (error "ELSE clause isn't last -- COND->IF" 
                        clauses)) 
             (if (extended-cond? first) 
                 (make-application (make-lambda '(_cond-parameter) 
                                                (make-if _cond-parameter 
                                                         (make-application (extended-cond-actions first) 
                                                                           _cond-parameter) 
                                                         (expand-clauses rest))) 
                                   (cond-predicate first)) 
                 (make-if (cond-predicate first) 
                          (sequence->exp (cond-actions first)) 
                          (expand-clauses rest))))))) 
  
 (define (extended-cond? clause) 
   (eq? (cadr (cond-actions clause)) '=>)) 
  
 (define (make-application function parameters) 
   (cons function parameters)) 
  
 (define (extended-cond-actions clause) 
   (caddr clause))