I have been playing about with The Little Schemer, and am trying ideas as i work through (not all of which are working out). Just now, i am in Chapter 6 (where they introduce helper functions) and i feel that a step is within reach -- i just don't know how to make that step.
The code from the book is as follows:
(define (^ b e) (expt b e))
(define (x a b) (* a b))
(define value-i
(lambda (nexp)
(cond
((atom? nexp) nexp)
((eq? (car (cdr nexp)) '+) (+ (car nexp) (value-i (caddr nexp))))
((eq? (car (cdr nexp)) 'x) (x (car nexp) (value-i (caddr nexp))))
(else
(^ (car nexp) (value-i (caddr nexp))))
)))
The following helpers are defined:
(define (operator-i aexp) (car (cdr aexp)))
(define (firstSubExp-i aexp) (car aexp))
(define (secondSubExp aexp) (caddr aexp))
And this simplification is made:
(define value-i2
(lambda (nexp)
(cond
((atom? nexp) nexp)
((eq? (operator-i nexp) '+) (+ (firstSubExp-i nexp)
(value-i2 (secondSubExp nexp))))
((eq? (operator-i nexp) 'x) (x (firstSubExp-i nexp)
(value-i2 (secondSubExp nexp))))
(else
(eq? (operator-i nexp) '^) (^ (firstSubExp-i nexp)
(value-i2 (secondSubExp nexp))))
)))
The simplification i think i can see is that as we assume all nexp
are valid, we don't need to repeat the ((eq? (operator-i nexp) ...
boilerplate.
Something like the following should work:
(define value-i3
(lambda (nexp)
(cond
((atom? nexp) nexp)
(else
((operator-i nexp)
(firstSubExp-i nexp)
(value-i3 (secondSubExp nexp))))
)))
... except that it does not. It errors out with Exception: attempt to apply non-procedure ...
(one of +, x and ^).
I can see that the problem is that it does not recognise that i am trying to call a function with (operator-i nexp)
.
How do i make clear to the interpreter that i wish to apply the function i am returning from (operator-i nexp)
?
Any other tips are also welcome (i am using petite chez scheme).
Unfortunately,
value-i3
doesn't work because(operator-i nexp)
returns a symbol, not a procedure object. Notice the difference between'+
and+
?There's not really an easy way to get around that (if we rule out
eval
, which is gross and disrecommended), other than using an alist to link the symbol with the procedure (or usingcase
orcond
as mentioned in Sylwester's answer):Then use
symbol->procedure
the same way as Sylwester's answer.If you find quasiquotes too difficult to read, you can use
list
andcons
directly;The OP asked for more information about
assq
and the like, so I thought I'd update the post directly. Basically,(assoc key alist)
returns the first item inalist
whosecar
isequal?
tokey
, or#f
otherwise;assq
andassv
are similar toassoc
but useeq?
andeqv?
as the comparison operator. So, here's a sample implementation (with R7RS/SRFI-1 semantics):