15.2 Cdr部での再帰
(defmacro alrec (rec &optional base)
"cltl2 version"
(let ((gfn (gensym)))
`(lrec #'(lambda (it ,gfn)
(symbol-macrolet ((rec (funcall ,gfn)))
,rec))
,base)))
- マクロ内でlrecを使ってたら意味ないじゃんて思った。
(defmacro with-gensyms (syms &body body)
`(let ,(mapcar #'(lambda (s) `(,s (gensym))) syms) ,@body))
(defmacro alrec (body &optional base)
(let ((g-it (intern "IT"))
(g-rec (intern "REC")))
(with-gensyms (g-fn g-items)
`(labels ((,g-fn (,g-items)
(if (null ,g-items)
,base
(symbol-macrolet ((,g-rec (,g-fn (cdr ,g-items))))
(let ((,g-it (car ,g-items)))
(declare (ignorable ,g-it))
,body)))))
#',g-fn))))
(defmacro on-cdrs (body base-expression &rest lsts)
`(funcall (alrec ,body ,base-expression) ,@lsts))
(defun maxmin (args)
(when args
(on-cdrs (multiple-value-bind (mx mn) rec
(values (max mx it) (min mn it)))
(values (car args) (car args))
(cdr args))))
(maxmin '(3 4 2 8 5 1 6 7))
8
1
15.3 部分ツリーでの再帰
- 同じくマクロ内でtrecを使っているので完全マクロ版。
(defmacro atrec (body-expression &optional (base 'it))
(let ((left (intern "LEFT"))
(right (intern "RIGHT"))
(it (intern "IT")))
(with-gensyms (g-fn g-tree)
`(labels ((,g-fn (,g-tree)
(let ((,it ,g-tree))
(declare (ignorable ,it))
(if (atom ,g-tree)
,base
(symbol-macrolet
((,left (,g-fn (car ,g-tree)))
(,right (if (cdr ,g-tree)
(,g-fn (cdr ,g-tree)))))
,body-expression)))))
#',g-fn))))
(defmacro on-trees (rec base &rest trees)
`(funcall (atrec ,rec ,base) ,@trees))
(defun count-leaves (tree)
(on-trees (+ left (or right 1)) 1 tree))
(count-leaves '(1 2 (3 4) (5 (6 7 (8)))))
->13
(defun count-leaves-atom (tree)
(on-trees (+ left (or right 0)) 1 tree))
(count-leaves-atom '(1 2 (3 4) (5 (6 7 (8)))))
->8