Common Lisp を独学で学ぼうとしており、マクロ作成の演習として、任意の深さのネストされた do ループを定義するマクロを作成しようとしています。私はemacsとスライムを使ってsbclを使っています。
まず、次の二重ループ マクロを作成しました。
(defmacro nested-do-2 (ii jj start end &body body)
`(do ((,ii ,start (1+ ,ii)))
((> ,ii ,end))
(do ((,jj ,ii (1+ ,jj)))
((> ,jj ,end))
,@body)))
次に、次のように使用できます。
(nested-do-2 ii jj 10 20 (print (+ ii jj)))
ところで、もともとこのマクロは gensym を使用してループ カウンター (ii、jj) を生成するように記述していましたが、ボディ内のカウンターにアクセスできなければ、このマクロはほとんど役に立たないことに気付きました。
とにかく、マクロを一般化して、任意のレベルにネストされるネストされた do ループを作成したいと思います。これは私がこれまでに得たものですが、うまくいきません:
(defmacro nested-do ((&rest indices) start end &body body)
`(dolist ((index ,indices))
(do ((index ,start (1+ index)))
((> index ,end))
(if (eql index (elt ,indices (elt (reverse ,indices) 0)))
,@body))))
私は次のように呼び出したいと思います:
(nested-do (ii jj kk) 10 15 (print (+ ii jj kk)))
ただし、リストが適切に展開されていないため、デバッガーで次のエラーが発生します。
error while parsing arguments to DEFMACRO DOLIST:
invalid number of elements in
((INDEX (II JJ KK)))
そして、それが明らかでない場合、埋め込まれた if ステートメントのポイントは、最も内側のループでのみ本体を実行することです。それは私にはあまりエレガントに見えず、実際にはテストされていません (パラメーターリストをまだ展開できていないため) が、実際にはこの質問のポイントではありません。
マクロ内でリストを適切に展開するにはどうすればよいですか? マクロの構文に問題がありますか、それとも関数呼び出しのリストの式に問題がありますか? その他のコメントもお待ちしております。
前もって感謝します。