Onlisp

15章 関数を返すマクロ

15.1 関数の構築
  • 引数ひとつだし、あまり強力でない気がする。
    • mapなどに使うのにはいいかもしれない。
    • ok
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
  • できた。
15.4 遅延評価
  • うわさの遅延評価ってこれなの?
    • なんか地味な印象。
    • 利用する対象がいまいち思いつかない。普通のクロージャーにみえる。
    • ok

16章 マクロを定義するマクロ

16.1 省略
  • 名前長いのがかっこいいんじゃないか!
    • 省略反対派
  • macro-macroの書き方はok。
  • プロジェクトの最初とかにリストとして書けるのがいい。
16.2 属性
(defmacro color (obj)
  `(get ,obj 'color))
  • こういう小さいマクロは有効。
    • あとでデータ構造を大規模に変更しても大丈夫だし、関数ではないのでオーバーヘッドもない。
  • propmacroは基本的に16.1と同じ。
16.3 アナフォリックマクロ
  • 大体ok
    • 最後の汎変数と混ざったところp225,6,7あたりが微妙にちゃんと理解できていないので後で復習する。

17章 リードマクロ

  • この章は前に読んだからOK
    • これを使えば、パースされる前のテキストの状態のプログラムも改変できる。