Search code examples
lispevalquote

Why isn't there an `unquote` Lisp primitive?


Lately, I've been thinking a lot about the basis of Lisp; I've read several manuals and/or other materials on the Internet, including The Roots of Lisp by P. ‎Graham:

In The Roots of Lisp, quote is described as a primitive that changes code into data, thereby quoting it, but there doesn't seem to be an equivalent inverse primitive, that is an unquote primitive. I thought it might have been eval's business, but eval often runs the data in a null lexical environment, which is not equivalent to changing data back into code.

Ergo, why isn't there an unquote Lisp primitive?


Solution

  • unquote is only useful in the context of quasiquote, and quasiquote can be implemented as a macro (that uses quote behind the scenes). So there's no need to have an unquote primitive; the quasiquote macro simply deals with unquote symbols as they are found.

    (quasiquote is the Scheme name for the backtick quote. Thus:

    `(foo bar ,baz)
    

    is read in as

    (quasiquote (foo bar (unquote baz)))
    

    in Scheme.)


    Here's a very simple Scheme quasiquote macro (it only handles lists, unlike standard quasiquote which also handles vectors and other data types):

    (define-syntax quasiquote
      (syntax-rules (unquote unquote-splicing)
        ((quasiquote (unquote datum))
         datum)
        ((quasiquote ((unquote-splicing datum) . next))
         (append datum (quasiquote next)))
        ((quasiquote (datum . next))
         (cons (quasiquote datum) (quasiquote next)))
        ((quasiquote datum)
         (quote datum))))
    

    Equivalent version using all the standard reader abbreviations:

    (define-syntax quasiquote
      (syntax-rules (unquote unquote-splicing)
        (`,datum
         datum)
        (`(,@datum . next)
         (append datum `next))
        (`(datum . next)
         (cons `datum `next))
        (`datum
         'datum)))