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-i3doesn'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 usingcaseorcondas mentioned in Sylwester's answer):Then use
symbol->procedurethe same way as Sylwester's answer.If you find quasiquotes too difficult to read, you can use
listandconsdirectly;The OP asked for more information about
assqand the like, so I thought I'd update the post directly. Basically,(assoc key alist)returns the first item inalistwhosecarisequal?tokey, or#fotherwise;assqandassvare similar toassocbut useeq?andeqv?as the comparison operator. So, here's a sample implementation (with R7RS/SRFI-1 semantics):