Lispはマクロと関数を区別する。同じ適用式でも、マクロの場合、引数を評価せずにASTのまま渡す。マクロ本体において、そのAST自体をLisp内の関数を用いてあれこれ処理し、ASTを返す。引数のASTの構造に手を入れられるため、文法そのものを拡張できる。マクロは式を返す。そしてその式自体がマクロ適用式の場合、評価されると更に別の式を返す。最終的にそれが関数適用から返された値となるまで、繰り返し評価を続ける。
Glispは、真にLisp的なマクロを提供しない。代わりに、その関数適用が1ステップ評価される際、どのようなASTが返されるべきかというアノテーションを関数本体に付与する機能を提供する。
例えば、円のPathオブジェクトを返す関数があるとする。
circle = (=> [center:Vec2 radius:Number]
'(path (M (Vec2 ~center.x ~(- center.y r)))
(C (Vec2 ...) ...)
...
(Z)))
これは、関数本体がquoteされているので、Path値そのものではなく、path関数の適用式 (path (M (Vec2...
のASTを返す。そしてそのASTが評価されることで、最終的にPath値が返される。
通常この関数が適用される場合、quote, unquoteといったアノテーションは無視され、ただ評価される。
しかし、この適用式がexpandされる場合、評価器はアノテーションに従って値ではなくASTを返す。
引数となる式は常にディープコピーされる。
map関数も本来こういう風にexpandされて欲しい。
(map inc [1 2 (+ 3 4)]) -> [(inc 1) (inc 2) (inc (+ 3 4))]