健全なマクロ
Hygenic macro(ハイジェニックマクロ)
https://ja.wikipedia.org/wiki/健全なマクロ
マクロ 処理の過程の過程で見かけ上同じに見える 識別子 が発生(名前が衝突)しても、意図しない問題が起こらないことが保証されているマクロのことである。
健全なマクロの機能を持たない プログラミング言語 では、マクロ展開 中に作成された変数の束縛によって、すでに存在する変数の 束縛 が隠されてしまう可能性がある(不健全なマクロ)。
code:c
#define incr(X) {int a=0; ++X;}
int main (void) {
int a=0, b=0;
incr(a);
incr(b);
printf("a=%d, b=%d\n", a, b);
return 0;
}
/* 展開後 */
int main (void) {
int a=0, b=0;
{int a=0; ++a;}
{int a=0; ++b;} /* ここで a が再宣言されている */
printf("a=%d, b=%d\n", a, b); /* a=0, b=1 */
return 0;
}
Common Lisp でも発生する可能性があり、その場合は gensym を使って回避した記憶 radish-miyazaki.icon
https://www.asahi-net.or.jp/~kc7k-nd/onlispjhtml/variableCapture.html
Clojure
https://qiita.com/lagenorhynque/items/1b4dbd82490729126e36
ちょうど探していた内容の記事があった radish-miyazaki.icon
以前に Clojure のマクロについてまとめた
https://www.notion.so/8-Macros-df04e73a427245ac81148bc5beb567fd?pvs=4#589f519251ba4507b026a9f196ed4e12
構文クォートの中で、名前空間の修飾のない名前にハッシュ記号(#)を付けると、Clojure はアンダースコアとユニークなIDを付けた名前を持つ、自動生成されたシンボル(auto-gensym)を作り出す。
code:clojure
(defmacro unless test then else
`(let x# ~test
(if (not x#)
~then
~else)))
(let x 10
(unless false
(printf "x: %s%n" x) ;; x: 10
(println "TRUE")))
(use 'clojure.walk)
;; 展開処理
(macroexpand-all '(let x 10
(unless false
(printf "x: %s%n" x)
(println "TRUE"))))
;; 展開結果
(let* x 10
(let* x__2__auto__ false
(if (clojure.core/not x__2__auto__)
(printf "x: %s%n" x)
(println "TRUE"))))
Rust
macro_rules! を用いた 宣言的マクロ は健全なマクロ
項目28:分別をもってマクロを使おう