Onlisp

12章 「汎変数」

概念
  • ok
  • lispらしくなってきた。
複数回の評価に関わる問題
  • 副作用コードを評価してから渡したいが、評価すると場所を表す式じゃなくなってしまう。
  • define-modify-macroは3個の引数を取る.
    • 定義したいマクロの名前
    • (汎変数の後に)取るかもしれない付加的な引数
    • 汎変数の新しい値を返す関数の名前
(define-modify-macro toggle () not)
  • ok
更に複雑なユーティリティ
(defmacro _f (op place &rest args)
  (multiple-value-bind (vars forms var set access)
    (get-setf-expansion place)
    `(let* (,@(mapcar #'list vars forms)
             (,(car var) (,op ,access ,@args)))
       ,set)))
  • _fはわかるが、pullとかpull-ifとかはdefine-modify-macroで定義できるじゃん
(define-modify-macro pull2 (obj &rest args)
  (lambda (place obj &rest args) (apply #'delete obj place args)))
  • とおもってたら、引数順が気に入らないからだと下に書いてあった。
    • 確かに引数順は重要である。
(defmacro sortf (op &rest places)
  (let* ((meths (mapcar #'(lambda (p)
                            (multiple-value-list
                              (get-setf-expansion p)))
                        places))
         (temps (apply #'append (mapcar #'third meths))))
    `(let* ,(mapcar #'list
                    (mapcan #'(lambda (m)
                                (append (first m)
                                        (third m)))
                            meths)
                    (mapcan #'(lambda (m)
                                (append (second m)
                                        (list (fifth m))))
                            meths))
       ,@(mapcon #'(lambda (rest)
                      (mapcar
                        #'(lambda (arg)
                            `(unless (,op ,(car rest) ,arg)
                               (rotatef ,(car rest) ,arg)))
                        (cdr rest)))
                  temps)
       ,@(mapcar #'fourth meths))))
(sortf > x (aref ar (incf i)) (car lst))
;展開形
(let* ((#:g1 x)
       (#:g4 ar)
       (#:g3 (incf i))
       (#:g2 (aref #:g4 #:g3))
       (#:g6 lst)
       (#:g5 (car #:g6)))
  (unless (> #:g1 #:g2)
    (rotatef #:g1 #:g2))
  (unless (> #:g1 #:g5)
    (rotatef #:g1 #:g5))
  (unless (> #:g2 #:g5)
    (rotatef #:g2 #:g5))
  (setq x #:g1)
  (system:set-aref #:g2 #:g4 #:g3)
  (system:set-car #:g6 #:g5))
  • これはすごい。ちょっと感動した。
  • これがlispの力か…。
インバージョンを定義する
  • get-setf-expansionの展開関数リストへの追加
  • (defsetf access-fn &rest rest)
  • ok