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

My approach just changes the way `expand-clauses` is handled. I don't do any of the evaluation and just create a separate `if` clause with its own expression.

```
(define (expand-clauses clauses env)
(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 clauses isn't
last: COND->IF"
clauses))
(if (eq? (car (cond-actions first)) '=>) ; <---- here
(make-if (cond-predicate first)
(list (cadr (cond-actions first))
(cond-predicate first))
(expand-clauses
rest
env))
(make-if (cond-predicate first)
(cond-actions first)
(expand-clauses
rest
env)))))))
```

This won't work, because (cond-predicate first) would be evaluated twice, and not necessarily to the same value.

It's neater to just revise cond-actions into

```
(define (cond-actions clause)
(if (eq? '=> (cadr clause))
(list (list (caddr clause) (cond-predicate clause)))
(cdr clause)))
```

`(define (eval-cond exp env) (let ((clauses (cdr exp)) (predicate car) (consequent cdr)) (define (imply-clause? clause) (eq? (cadr clause) '=>)) (define (else-clause? clause) (eq? (car clause) 'else)) (define (rec-eval clauses) (if (null? clauses) 'false; checked all, no else-clause (let ((first-clause (car clauses))) (cond ((else-clause? first-clause) (eval-sequence (consequent first-clause) env)) ((imply-clause? first-clause) (let ((evaluated (eval (predicate first-clause) env))) (if (true? evaluated) (apply (eval (caddr first-clause) env) (list evaluated)) 'false))) (else (if (true? (eval (predicate first-clause) env)) (eval-sequence (consequent first-clause) env) 'false)))))) (rec-eval clauses)))`

lockywolf

This procedure works, but is not compatible with the SICP's definition of eval:

`(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ((cond? exp) (eval (cond->if exp) env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp))))`

That is, it doesn't transform cond syntactically.

dzy

but we can change the dispatch process in eval.. it's not a big deal.

`(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ;((cond? exp) (eval (cond->if exp) env)) ((cond? exp) (eval-cond exp env)) ((and? exp) (eval (and->if exp) env)) ((or? exp) (eval (or->if exp) env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp))))`