This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

problem with assoc

8 posts · 12009 views

I am trying to write a calculator procedure for the little schemer .. I have one procedure that works
(define value
  (lambda (n)
    (if (atom- n)
	n
	(if (eq? (car (cdr n)) '0+)
	    (0+ (car n)(value (car (cdr (cdr n)))))
	    (if (eq? (car (cdr n)) '0*)
		(0* (car n)(value (car (cdr (cdr n)))))
		(if (eq? (car (cdr n)) '0-)
		    (0- (car n)(value (car (cdr (cdr n)))))
		    (if (eq? (car (cdr n)) '0/)
			(0/ (car n)(value (car (cdr (cdr n)))))
			(if (eq? (car (cdr n)) '0^)
			    (0^ (car n)(value (car (cdr (cdr n)))))
			#f))))))))
so I tried another method that does not work
(define alist '((0+ 0+)(0* 0*)(0- 0-)(0/ 0/)(0^ 0^)))

(define value
  (lambda (n)
    (if (atom- n)
	n
	 (let ((f (assq (car (cdr n)) alist)))
	   (if (or (eq? (car (cdr n)) '0+)
		   (eq? (car (cdr n)) '0*)
		   (eq? (car (cdr n)) '0-)
		   (eq? (car (cdr n)) '0/)
		   (eq? (car (cdr n)) '0^))
	       (f (car n) (value (car (cdr (cdr n)))))
	       #f)))))
the error message for example (value '(3 0+ 4)) has ERROR: in procedure (#{0=}# ... wrong type to apply .. when I try (assoc '0+ alist) I get (#{0+}# . #{0+}#) so this is where my problem is .. but why?

Re: problem with assoc

Each element of the association list is a list, so you want 'f' to be some element of that list—the second element, I guess? I mean, it's redundant to be mapping each symbol to itself.

Re: problem with assoc

You are doing a very typical mistake of confusing symbols with bound procedures.Your alist must bedefined so that the value is a procedure and not just a symbol. Thus the symbol needs to be evaluated on the right hand side:
(define alist `((0+ ,0+)(0* ,0*)(0- ,0-)(0/ ,0/)(0^ ,0^)))
As you probably know this is just syntax sugar for:
(define alist (list (list '0+ 0+) (list '0* 0*)(list '0- 0-)(list '0/ 0/)(list '0^ 0^)))
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: problem with assoc

I have re written my code
(define a-list `((+ ,0+)(* ,0*)(- ,0-)(/ ,0/)))
and
(define val-
  (lambda (n)
    (if (atom- n)
	n
	(lambda f
	  (f (car n)(val- (car (cdr (cdr n)))))
	  (assoc (car (cdr n)) a-list)))))

;;; or 

(define val
  (lambda (n)
    (if (atom- n)
	n
	(let ((f ((car (cdr (assoc (car (cdr n)) a-list))))))
	  (f (car n)(val (car (cdr (cdr n)))))))))
but still get an error (val- '(3 + 4)) #<procedure 1e50de0 at <current input>:71:8 f. I am assuming that the lambda or let of f is the problem .. I have been looking online on how to access the a-list and use it to generate a procedure with no success.

Re: problem with assoc

val- doesn't make sense.. If it's an atom return the atom if not return a procedure..

In val you have double parentheses in an expression so the 0+ is applied with zero arguments and the result is then stored as f. It's most likely a number so then you are trying to apply it as a procedure.

Another thing I see is that your evaluator doesn't evaluate the first argument.. Thus '(+ (- 3 1) (- 3 2)) would fail.. In the default case your evaluator must find the procedure, then evaluate the second and third argument since both can be expressions. In the end you need to apply the values like this:
(define (evaluator expression)
  (if (atom? expression)
      expression
      (let ((proc (find-proc (car expression)))
            (arg1 (evaluator (cadr expression)))
            (arg2 (evaluator (caddr expression))))
        (proc arg1 arg2))))

(evaluator '(+ (- 3 1) (- 3 2))) ;==> 3
The assoc:
(define *procedures* `((+ ,+)(* ,*)(- ,-)(/ ,/)))
(define *sym* '+)
(assoc *sym* *procedures*) ; ==> (+ #procedure)
((cadr (assoc *sym* *procedures*)) 1 3) ; ==> 4
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: problem with assoc

with a lot of help on irc groovy2shoes in particular I came up with
(define a-list `((+ . ,0+)(* . ,0*)(- . ,0-)(/ . ,0/)(0^ . ,0^)))

;;; where 0+ etc are prewritten procedures could have used + - 

(define value
  (lambda (n)
    (if (atom- n)
	n
	(let ((op (car (cdr n))))
	  (let ((f (assq op a-list)))
	    (if f
		((cdr f)(car n)(value (car (cdr (cdr n)))))
		#f)))))
and managed to simplify it down to ..
(define value
  (lambda (n)
    (if (atom- n)
	n
	((lambda (f)
	   (if f
	       (f (car n)(value (caddr n)))
	       #f))
	 (cdr (assq (cadr n) a-list))))))
this code is good for questions of (2 + (3 * 4)) type and things like (+ (2 + 3)(3 * 4)) are a seperate procedure in the litte schemer where I got the inspiration for this procedure from.

the real question for me now is why the association list has to be written the way it is with dot notation ..

thanks for all the help .. really appreciated

Re: problem with assoc

It doesn't. If you look at the code snipplet I gave I waste an extra cons for each element just because your original question does not use dotted list but lists of proper lists.

These are the same and makes a list of two elements
(cons '+ (cons + '())) 
`(+ . (,+ . ()))
`(+ ,+)
; ==> (+ #procedure:+)
(car `(+ ,+)) ; ==> +
(cadr `(+ ,+)) ; ==> #procedure:+
The elements you ended up with saves one cons by storing the two values in car and cdr, a single pair:
(cons '+ +)
`(+ . ,+)
; ==> (+ . #procedure:+)
(car `(+ . ,+)) ; ==> +
(cdr `(+ . ,+)) ; ==> #procedure:+
Thus in your own procedure to use lists instead of dotted you would need to replace one cdr with a cadr. However if you don't you get a list of one procedure instead of a procedure.
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: problem with assoc

thanks a lot .. ya I feel like a dummy :) all good info thanks again