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?
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)))
I am also relatively new to Lisp, but I think that what you were thinking about is eval
. eval
is the way to change data back to code.
Namely, consider a simple function.
(defun foo (a b c) (list a b c))
Then, if you do something like this, you get a list of symbols:
CL-USER> (foo 'a 'b 'c)
(A B C)
If you add a quote in the front, the function call itself is treated as a piece of data (list):
CL-USER> '(foo 'a 'b 'c)
(FOO 'A 'B 'C)
Adding one more quote has an expected effect:
CL-USER> ''(foo 'a 'b 'c)
'(FOO 'A 'B 'C)
Let us now unwind it with eval
, which in essence may be thought of as the inverse operation for the quote
. It is the inverse. The x-axis is the data form. The y-axis is the code form. Hopefully this (somewhat stretched) analogy makes sense.
CL-USER> (eval ''(foo 'a 'b 'c))
(FOO 'A 'B 'C)
Can you guess what will happen if I chain two eval
s in a row?
Here it is:
CL-USER> (eval (eval ''(foo 'a 'b 'c)))
(A B C)