S式で書くOCamlもっとマクロのこと以下にもっと複雑なマクロについて紹介します。すべてcommon.scmで定義済みのマクロのサンプルとなります。「こういうこともできる」というマクロ拡張の参考にしてください。9))標準ライブラリで定義されているList.mapやList.map2の可変長引数版です。common.scmでは逆順にする「list-rev-map-n」やlistを返さない「list-iter-n」も定義済みです。anaphoricマクロdefine-macroで定義されたマクロの生成する式は割り込ませた変数の衝突についてプログラマ自身が注意を払う必要があります。これはdefine-macroの持つ危険性ではありますが、同時に強力な性質でもあります。以下のマクロは意図的にマクロの用意した変数名にパラメータを束縛して割り込ませています。いった任意の変数名での割り込みは実質的に予約語の拡張のような用途での利用が可能です。マクロサンプルanaphoric-argsは「第一引数に関数を受け取る関数(List.mapやList.iter等)」を受け取ります。6))これは「List.iter2」に渡す関数をマクロで生成しています。その関数は「_1」や「_2」といった連番の引数を自動生成します。(C++経験者ならboost::lambdaを連想するかもしれません)前述の「anaphoric-args」「list-map-n」は組み合わせて使うことも可能です。9)))この例では3つのlistのそれぞれn番目の要素を足し合わせたlistを返します。用途が自明でかつ横着に書きたい場合には便利かもしれません。厳密には可変長引数の関数ではなく、可変長引数のマクロを定義します。defun-varargsは、マクロを定義するマクロということになります。仮引数の記法はSchemeの可変長引数を参考にしています。以下の例では変数optで参照可能です。任意の数の引数をlistとして受け取ります。以下の例では変数argsで参照可能です。5)リストの内包表記(組み込みリスト用)Schemeのsrfi-42を参考にしています。list-ecマクロの中に式を並べることでlistの生成を行います。y))」のように列挙すると最後の式を評価した結果がlist-ecの返すlistの要素となります。x)(print_newline))ls2)関数の合成composeマクロは複数の関数を合成して新たな関数を返します。3))))」と等価になります。後ろのほうの関数から順に適用されていることに注意してください。3))契約プログラミング関数の引数、戻り値のチェックを体系的に行うための機能です。EiffelやD言語の持つ機能ですが、マクロサンプルのcontract-funはD言語を参考に実装してあります。例外Contract_assert_failureが投げられます。上記の例では「第一引数が4未満」「戻り値が10未満」という条件が課されています。条件はどちらかが不要であれば「in」か「out」のどちらか片方だけでも問題ありません。5)))(print_newline)Haskellには仮引数にリテラルを記述した同名の関数定義を列挙することで実引数が仮引数の値にマッチした物を呼び出す機能があります。これはその機能をマクロで再現してみたものになります。遅延リスト遅延リストは組み込みのデータ型では無いため「common.scm」には含まれません。result.ml遅延リストライブラリ「lazyList.ml」に関してはこちらのサイト(ブログ)のコードを使わせていただきました。以下のマクロは、より実験的なマクロ機構です。どこが実験的かというと、私が元々の仕様を勘違いして実装している可能性があります。syntax-case現時点でのSchemeの最新仕様であるR6RSで規定されたマクロ機構です。define-macroの柔軟性と、syntax-rulesの簡潔さと安全性を両立したマクロ機構です。RenamingSchemeの標準仕様では規定されていないマクロ機構です。使い勝手はdefine-macroに近く、define-macroのgensymとは別のやり方で変数名の衝突を回避します。以下に各種マクロ機構の変数衝突回避の違いのわかる例を列挙しておきます。どれも2つの参照型変数の値を入れ替えるものですが、一時変数「tmp」の扱いの違いを参考にしてください。