関数 list を呼ぶ回数だけを考えても、あまり大きなマクロを書くのは、うまくありま せん。前に記した for の例は(妥当な)リストの深さの(ほぼ)限界を示しています。 (このような)フォームを書くのをたやすくするため、マクロ ` (バッククォートと呼 ぶ)が与えられています。
バッククォートはリストをクォートしますが、リストの要素を選択的に評価します。こ れは(その一番単純なフォームにおいて)特殊フォーム quote と同じ働きをします。以 下に示す 2つのフォームは、同じ結果になります。
(` (a list of (+ 2 3) elements))
=> (a list of (+ 2 3) elements)
(quote (a list of (+ 2 3) elements))
=> (a list of (+ 2 3) elements)
バッククォートに対するアーギュメント中に特別なマーカー (,) を入れることで、 アーギュメントの(評価させたい)部分のみを評価させることができます。
(list 'a 'list 'of (+ 2 3) 'elements)
=> (a list of 5 elements)
(` (a list of (, (+ 2 3)) elements))
=> (a list of 5 elements)
特別なマーカー (,@) を用いることで、リストを評価し(要素にするのではなく) 結果 のリストに組み込む(訳注:splice in)こともできます。
(cons 1 (list (+ 1 1) (+ 1 2)))
=> (1 2 3)
(` (1 (,@ (list (+ 1 1) (+ 1 2)))))
=> (1 2 3)
;; もっとひどい例
(cons 'a
(cons 'list
(cons 'of (append (list (+ 2 3)) '(elements)))))
=> (a list of 5 elements)
(` (a list of (,@ (list (+ 2 3))) elements))
=> (a list of 5 (elements)) ?????
=> (a list of 5 elements)
これにより、for マクロは (より明確に)次のように書き直すことができます。
(defmacro for (var from init to final fo &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(` (let (( (, var) (, init) ))
(while (<= (, var) (, final))
(,@ body)
(inc (, var))
))))
=> for
Macro: ` list
このマクロは、quote が行なうように list を返します。違いは、特別なマーカー (,) で始まるサブリストはその 2番目の要素を評価し、特別なマーカー (,@) で始 まるサブリストはその 2番目の要素を評価しその結果を新しく作られるリストに組 み込む点です。
このような特別なマークを付けられたサブリストが 2つ以上の要素を持つ場合、そ の要素は無視されることになります。
??避けられなくてはいけない微妙なバグがいくつかあります。以下のフォームは期 待するようには動きません。
(` (a . (, 1))) => (a \, 1) ; (a . 1) でない
(` [a (, 1) c]) -> ERROR: Wrong type argument ; [a 1 c] でない (` (, 2)) => (\, 2) ; 2 でない