Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

eval

lisp

quote

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?

like image 764
SaltyEgg Avatar asked Jan 02 '26 04:01

SaltyEgg


2 Answers

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)))
like image 62
Chris Jester-Young Avatar answered Jan 06 '26 01:01

Chris Jester-Young


I am also relatively new to Lisp, but I think that what you were thinking about is eval. evalis 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 evals in a row? Here it is:

CL-USER> (eval (eval ''(foo 'a 'b 'c)))
(A B C)
like image 27
MadPhysicist Avatar answered Jan 05 '26 23:01

MadPhysicist



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!