#:g1: 実践SETF定義:define-modify-macroで頻出パターンをまとめる

Posted 2018-12-13 14:28:27 GMT

Lisp SETF Advent Calendar 2018 13日目 》

setf系構文の紹介ですが、今回は、define-modify-macroの紹介です。

define-modify-macroは、簡単に説明するなら、(setq x (fn x))のようなパターンを簡潔に(fnf x)と書けるようにする便利定義構文なのですが、このようなパターンが頻出する訳でもないので、普段はそんなに使うこともない印象があります。

define-modify-macroで何か定義してみる

(setq x (cdr x))

というパターンはそこそこ使いますが、define-modify-macrocdrfでも定義してみましょう。

(define-modify-macro cdrf () cdr)

(let ((x (list 0 1 2))) (cdrf x) x)(1 2)

まあ、実質同じことをするビルトインマクロにpopがありますが……。
一応返り値が違います。

定義構文の注意点として、代入にされる場所となる変数が先頭に来て、さらにそれが定義構文中には現われない、という点です。
cdrの場合は1引数なので、0引数で記述します。

define-modify-macroを使えば役に立ちそうな立たなそうな構文を大量生産できます。

(define-modify-macro listf (&rest args) list)

(let ((x (list 0 1 2))) (list x 1 2))((0 1 2) 2 3 4)

(define-modify-macro =f (&rest args) =)

(let ((x 0) (y 1)) (=f x y ) (list x y))(nil 1)

appendfnconcf等々は定番アイテムで、色々なユーティリティライブラリに含まれています。
まあ、ライブラリを読み込むのが面倒な場合には、簡単なので定義してしまっても良いでしょう。

modify-macrolet

define-modify-macroは大域定義になるのですが、7年程前にローカル構文版を思い付いて作ったことがありました。

これを使うと、

(modify-macrolet ((nconcf (&rest args) nconc))
  (let ((x nil))
    (nconcf x (list 0 1 2 3))
    x))

のように大域の名前を汚染することなくローカルに書くことが可能になります。

ちなみに、個人的には定義してから7年間一度も使ったことはありませんが、ご興味のある方は如何でしょうか。
また、modify-macroletを自作してみるのも一興かなと思います。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus