For Gauche 0.9.9

Next: , Previous: , Up: Core syntax   [Contents][Index]

### 4.9 Quasiquotation

Special Form: quasiquote template

[R7RS base] Quasiquotation is a convenient way to build a structure that has some fixed parts and some variable parts. See the explanation below.

Reader Syntax: ``template`

[R7RS] The syntax ``x` is read as `(quasiquote x)`.

Special Form: unquote datum …
Special Form: unquote-splicing datum …

[R7RS base] These syntaxes have meaning only when they appear in the template of quasiquoted form. R5RS says nothing about these syntaxes appear outside of quasiquote. Gauche signals an error in such case, for it usually indicates you forget quasiquote somewhere.

R5RS only allows `unquote` and `unquote-splicing` to take a single argument; it is undefined if you have `(unquote)` or `(unquote x y)` inside quasiquoted form. R6RS allows zero or multi-arguments, and Gauche follows that.

Reader Syntax: `,datum`
Reader Syntax: `,@datum`

[R7RS] The syntaxes `,x` and `,@x` are read as `(unquote x)` and `(unquote-splicing x)`, respectively.

#### Quasiquote basics

Suppose you want to create a list `(foo bar x y)`, where `foo` and `bar` are symbols, and x and y are the value determined at runtime. (For the sake of explanation, let’s assume we have variables x and y that provides those values.) One way to do that is to call the function `list` explicitly.

```(let ((x 0) (y 1))
(list 'foo 'bar x y)) ⇒ (foo bar 0 1)
```

You can do the same thing with quasiquote, like this:

```(let ((x 0) (y 1))
`(foo bar ,x ,y))  ⇒ (foo bar 0 1)
```

The difference between the two notations is that the explicit version quotes the parts that you want to insert literally into the result, while the quasiquote version unquotes the parts that you don’t want to quote.

The quasiquote version gets simpler and more readable when you have lots of static parts with scattered variable parts in your structure.

That’s why quasiquote is frequently used with legacy macros, which are basically a procedure that create program fragments from variable parts provided as macro arguments. See the simple-minded `my-if` macro that expands to `cond` form:

```(define-macro (my-if test then else)
`(cond (,test ,then)
(else ,else)))

(macroexpand '(my-if (< n 0) n (- n)))
⇒ (cond ((< n 0) n) (else (- n)))
```

Note the two `else`s in the macro definition; one isn’t unquoted, thus appears literally in the output, while another is unquoted and the corresponding macro argument is inserted in its place.

Of course you can use quasiquotes unrelated to macros. It is a general way to construct structures. Some even prefer using quasiquote to explicit construction even most of the structure is variable, for quasiquoted form can be more concise. Gauche also tries to minimize runtime allocation for quasiquoted forms, so it may potentially be more efficient; see "How static are quasiquoted forms?" below.

#### Splicing

When `(unquote-splicing expr)` appears in a quasiquoted form, expr must evaluate to a list, which is spliced into the surrounding context. It’s easier to see examples:

```(let ((x '(1 2 3)))
`(a ,@x b)) ⇒ (a 1 2 3 b)

(let ((x '(1 2 3)))
`(a ,x b)) ⇒ (a (1 2 3) b)

(let ((x '(1 2 3)))
`#(a ,@x b)) ⇒ #(a 1 2 3 b)
```

Compare the unquote version and unquote-splicing version. Splicing also works within a vector.

#### Multi-argument unquotes

If `unquote` or `unquote-splicing` takes multiple arguments, they are interpreted as if each of its arguments are unquoted or unquote-spliced.

```;; This is the same result as `(,(+ 1 2) ,(+ 2 3) ,(+ 3 4))
`((unquote (+ 1 2) (+ 2 3) (+ 3 4)))
⇒ (3 5 7)

;; This is the same result as
;;   `(,@(list 1 2) ,@(list 2 3) ,@(list 3 4))
`((unquote-splicing (list 1 2) (list 2 3) (list 3 4)))
⇒ (1 2 2 3 3 4)

;; Edge cases
`((unquote))          ⇒ ()
`((unquote-splicing)) ⇒ ()
```

It is an error for zero or multiple argument `unquote`/`unquote-splicing` forms appear which you cannot splice multiple forms into.

```;; Multiple arguments unquotes are error in non-splicing context
`(unquote 1 2)          ⇒ error
`(unquote-splicing 1 2) ⇒ error
```

Note that the abbreviated notations `,x` and `,@x` are only for single-argument forms. You have to write `unquote` or `unquote-splicing` explicitly for zero or multiple argument forms; thus you don’t usually need to use them. These forms are supported mainly to make the nested unquoting forms such as `,,@` and `,@,@`—R5RS cannot handle the case the inner unquote-splicing form expands into zero or multiple forms.

#### How static are quasiquoted forms?

When quasiquoted form contains variable parts, what happens at runtime is just the same as when an explicit form is used: ``(,x ,y)` is evaluated exactly like `(list x y)`. However, Gauche tries to minimize runtime allocation when a quasiquoted form has static parts.

First of all, if there’s no variable parts in quasiquoted form, like ``(a b c)`, the entire form is allocated statically. If there is a static tail in the structure, it is also allocated statically; e.g. ``((,x a b) (,y c d))` works like `(list (cons x '(a b)) (cons y '(c d)))`.

Furthermore, when an unquoted expression is a constant expression, Gauche embeds it into the static form. If you’ve defined a constant like `(define-constant x 3)`, then the form ``(,x ,(+ x 1))` is compiled as the constant `'(3 4)`. (See Definitions, for the explanation of `define-constant` form.)

In general it is hard to say which part of quasiquoted form is compiled as a static datum and which part is not, so you shouldn’t write a code that assumes some parts of the structure returned from quasiquote are freshly allocated. In other words, you better avoid mutating such structures.

Next: , Previous: , Up: Core syntax   [Contents][Index]