健全なマクロ

健全なマクロ（）とは、マクロ処理の過程の過程で見かけ上同じに見える識別子が発生（名前が衝突）しても、意図しない問題が起こらないことが保証されているマクロである。SchemeやDylanなどのプログラミング言語はこの機能を持っている。マクロ処理の過程で見かけ上同じに見える識別子が発生するという問題は、健全なマクロが導入される以前からLISPコミュニティで広く知られていた。マクロの作者は、プログラムコード中の他のどれとも異なるユニークな識別子を生成する gensym などの組み込み関数を使ってプログラマーが明示的に回避したり、通常使用されないような長くて複雑な名前の識別子を用いることでこの問題の可能性を低減させてきた。健全なマクロはこの問題を解決する方法をマクロの展開機能に組み込むことで問題を根本的に解決している。「健全」を意味する「」という語は、コールベッカーらが1986年に書いた健全なマクロの展開を導入した論文で、数学の用語の影響を受けて初めて使用された。

健全でないマクロ 
健全なマクロの機能を持たないプログラミング言語では、マクロの展開中に作成された変数の束縛によって、すでに存在する変数の束縛が隠されてしまう可能性がある。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 ;
    }C言語のプリプロセッサで上のコードを変換すると、次のコードが生成される。int main (void)
    {
    int a=0, b=0 ;
    {int a=0; ++a ;}
    {int a=0; ++b ;}
    printf("a=%d, b=%d\n", a, b) ;
    return 0 ;
    }main のスコープで宣言された変数 a は、マクロの中にある変数 a によって隠されてしまっている。その結果、プログラムを実行しても変数の値は変化せず、コンパイルされたプログラムは次のように出力する。
a=0, b=1

健全なマクロ
健全なマクロとは、処理系がすべての識別子（関数名、変数名、if、while など）についてそれぞれが所属する文脈の情報を考慮してする（つまり識別子がレキシカルスコープが保証される）マクロである。この性質は「参照透過性」と呼ばれている。健全なマクロを使用している Scheme などの言語は、マクロ展開の処理の一部として自動的に参照透過性を保証することで、見かけ上同じにみえる識別子でもそれぞれが所属する文脈を加味して処理することで、プログラムは意図通りに動作することが保証されている。ただし、識別子を意図的に補足するために、健全なマクロのメカニズムを明示的に無視できるようにしている実装もある。

たとえば、次のSchemeによるmy-unless の実装は、期待通りの振る舞いをする。(define-syntax my-unless
  (syntax-rules ()
    [(_ condition body ...)
      (if (not condition) ;; 大域的な名前空間に所属する not: 論理否定を意味する本来の定義である。
        (begin body ...)
      )
    ]
  )
)

(let ([not (lambda (b) b)]) ;; 局所的な名前空間に所属する not: 論理否定を意味する本来のものとは異なる定義である。
  (my-unless #t
    (display "この文は出力されることはない！") (newline)
  )
)

脚注

参考文献 
 On Lisp, Paul Graham
 syntax-rules on schemewiki
 syntax-case on schemewiki
 examples of syntax-case on schemewiki
 syntactic closures on schemewiki
 simpler-macros on schemewiki
 examples of simpler-macros on schemewiki
 Writing Hygienic Macros in Scheme with Syntax-Case

プログラミング
ソフトウェア
Scheme