[CM] c?r?

Bill Schottstaedt bil at ccrma.Stanford.EDU
Fri Apr 9 12:01:00 PDT 2010


I was grumbling to myself that no one should have to count
cars and cdrs, then thought of this macro:

 (define-macro (c?r path)
      ;; here "path" is a list and "X" marks the spot in it that we are trying to access
      ;; (a (b ((c X)))) -- anything after the X is ignored, other symbols are just placeholders
      ;; c?r returns a function that gets X
      
      ;; (c?r (a b X)) -> caddr, 
      ;; (c?r (a (b X))) -> cadadr
      ;; ((c?r (a a a X)) '(1 2 3 4 5 6)) -> 4
      ;; ((c?r (a (b c X))) '(1 (2 3 4))) -> 4
      ;; ((c?r (((((a (b (c (d (e X)))))))))) '(((((1 (2 (3 (4 (5 6)))))))))) -> 6
      ;; ((c?r (((((a (b (c (X (e f)))))))))) '(((((1 (2 (3 (4 (5 6)))))))))) -> 4
      ;; (procedure-source (c?r (((((a (b (c (X (e f))))))))))) -> (lambda (lst) (car (car (cdr (car (cdr (car (cdr 
(car (car (car (car lst))))))))))))
      
      (define (X-marks-the-spot accessor tree)
	(if (pair? tree)
	    (or (X-marks-the-spot (cons 'car accessor) (car tree))
		(X-marks-the-spot (cons 'cdr accessor) (cdr tree)))
	    (if (eq? tree 'X)
		accessor
		#f)))
      
      (let ((accessor (X-marks-the-spot '() path)))
	(if (not accessor)
	    (error "can't find the spot! ~A" path)
	    (let ((len (length accessor)))
	      (if (< len 5)                   ; it's a built-in function
		  (let ((name (make-string (+ len 2))))
		    (set! (name 0) #\c)
		    (set! (name (+ len 1)) #\r)
		    (do ((i 0 (+ i 1))
			 (a accessor (cdr a)))
			((= i len))
		      (set! (name (+ i 1)) (if (eq? (car a) 'car) #\a #\d)))
		    (string->symbol name))
		  (let ((body 'lst))          ; make a new function to find the spot
		    (for-each
		     (lambda (f)
		       (set! body (list f body)))
		     (reverse accessor))
		    `(lambda (lst) ,body)))))))
    



More information about the Cmdist mailing list