やりたいことをするマクロ
ある種の演習として:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
今すぐ試してください:
(setq-every "/foo/bar" f-loc1 f-loc2)
仕組み
人々は(コメントによると)どのように機能するのか興味があるので、ここに説明があります。マクロの書き方を実際に学ぶには、優れたCommon Lispの本を選んでください(そう、Common Lispは、Emacs Lispでも同じことができますが、Common Lispはもう少し強力で、より良い本があります、IMHO)。
マクロは生のコードで動作します。マクロは引数を評価しません(関数とは異なります)。ですから、ここでは未評価でvalue
ありvars
、マクロのコレクションは単なるシンボルです。
progn
複数のsetq
フォームを1つにグループ化します。このこと:
(mapcar (lambda (x) (list 'setq x value)) vars)
setq
OPの例を使用して、フォームのリストを生成するだけです。
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
ご覧のとおり、フォームはバッククォート形式の内側にあり、プレフィックスとしてカンマが付いています
,
。逆引用符で囲まれたフォーム内では、すべてが通常どおり引用されますが、,
一時的に「mapcar
有効化」評価されるため、マクロ展開時に全体が評価されます。
最後にsを使用して@
リストから外側の括弧を削除するsetq
ため、次のようになります。
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
マクロはソースコードを任意に変換できますが、素晴らしいことではありませんか?
警告
このマクロは基本的に次のように展開されるため、小さな警告があります。最初の引数は数回評価されます。
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
ここに変数または文字列がある場合は問題ありませんが、次のように記述した場合:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
次に、関数が複数回呼び出されます。これは望ましくない場合があります。once-only
(MMTパッケージで利用可能)を使用し
て修正する方法は次のとおりです。
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE.
VALUE is only evaluated once."
(mmt-once-only (value)
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars))))
そして、問題はなくなりました。