Flux
Flux

Reputation: 10910

Behavior of "unquote" when used as the second to last symbol in a quasiquoted proper list

I am trying to produce the list (1 unquote 2) using quasiquote. I have tried this:

`(1 unquote 2)

However, in Racket, MIT Scheme and Chez Scheme, I get a dotted list: '(1 . 2).

So I tried this:

`(1 'unquote 2)

However, I get (1 'unquote 2).

I finally got the list I wanted using this technique:

`(1 unquote 2 ,((lambda (x) x) 'unquote) 2)  ; Returns: '(1 unquote 2)

Why do I get a dotted list out of a quasiquoted proper list when unquote is the second to last element in the quasiquoted list?

Actually, it does not always produce a dotted list. For example:

`(1 unquote (list 2 3 4))  ; Returns: '(1 2 3 4)

Please explain this strange behavior of unquote when it is the second to last element in a quasiquoted list.

Upvotes: 1

Views: 248

Answers (3)

Metaxal
Metaxal

Reputation: 1113

[writing an answer rather than a comment because it's impossible to format backticks properly in a comment. Lisp/Scheme still handles this better than markdown ;-) ]

As others have explained (esp. Sorawee), unquote (aka ,) is a special name that is treated specially when inside an quasiquoted list (aka the backtick). To prevent its special meaning, a simple workaround is to make sure the special name doesn't appear textually. Note that unquote does not have a special meaning inside quote (by contrast to inside quasiquote).

Thus this will work in all variants of Scheme:

(define unquote-sym 'unquote) ; `unquote` is inside `quote`, so it's a mere symbol here

`(1 ,unquote-sym 2) ; '(1 unquote 2)

Upvotes: 0

Sorawee Porncharoenwase
Sorawee Porncharoenwase

Reputation: 6502

(a b c) is a shorthand for (a . (b . (c . ()))).

So (quasiquote (1 unquote 2)) is really (quasiquote (1 . (unquote 2))) which is '(1 . 2).

(Or if you want to fully expand it, (quasiquote (1 unquote 2)) is (quasiquote . ((1 . (unquote . (2 . ()))) . ())))

Similarly, (quasiquote (1 unquote (list 2 3 4))) is really (quasiquote (1 . (unquote (list 2 3 4)))) = (quasiquote (1 . (2 3 4))) = '(1 2 3 4).

By the way, an easier way to produce '(1 unquote 2) using quasiquote is:

`(1 ,'unquote 2)

Upvotes: 2

molbdnilo
molbdnilo

Reputation: 66371

According to R5RS,

Unpredictable behavior can result if any of the symbols quasiquote, unquote, or unquote-splicing appear in positions within a <qq template> otherwise than as described above.

And your positions are not "as described above" - the form must be (unquote expression ...).

It has been upgraded to a syntax violation in R6RS.

Upvotes: 1

Related Questions