Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backquote in Common Lisp: read and eval

This question is somewhat replated to this and this for Elisp. Basically, how is the back-quote read and evaluated? What processes are happening? And does the standard say anything about it?

Here is what I would expect, but it doesn't happen: symbol ` is a reader-macro and is translated into some kind of (BACKQUOTE ...) macro/special form (similarly to ' being translated to (QUOTE ...)). This doesn't happen, and, in fact, Common Lisp doesn't even have a BACKQUOTE macro.

What is happening (SBCL):

CL-USER> (defparameter *q* (read-from-string "`(a b ,c)"))
*Q*
CL-USER> *q*
`(A B ,C)
CL-USER> (car *q*)
SB-INT:QUASIQUOTE
CL-USER> (cdr *q*)
((A B ,C))

Something different from expected, but OK. Now, ,C is an interesting beast on its own:

CL-USER> (type-of (third (cadr *q*)))
SB-IMPL::COMMA

If there are no comma-symbols, evaluating the read expression is fine:

CL-USER> (eval (read-from-string "`(a b c)"))
(A B C)

But if I want to evaluate the original expression even with local binding for C, there is a problem:

(let ((c 10)) (eval (read-from-string "`(a b ,c)")))
; in: LET ((C 10))
;     (LET ((C 10))
;       (EVAL (READ-FROM-STRING "`(a b ,c)")))
; 
; caught STYLE-WARNING:
;   The variable C is defined but never used.
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
; Evaluation aborted on #<UNBOUND-VARIABLE C {1007A3B2F3}>.

This means that EVAL didn't pick up the environment in which C is bound.

PS. Interestingly enough, in Elisp this works.

like image 956
mobiuseng Avatar asked Mar 05 '16 10:03

mobiuseng


1 Answers

Backquote

Backquote is a standard macro character in Common Lisp.

In Common Lisp the representation of a backquote expression is undefined. Implementations actually use different representations. What you see for SBCL is implementation specific.

EVAL

The problem you have with eval is fully unrelated to the reader or backquote expressions:

? (let ((c 10))
    (eval '(list 'a 'b c)))

Error: The variable C is unbound.

In Common Lisp EVAL is using the dynamic environment and the null lexical environment for evaluation of forms. Above lexical environment, where c is bound to 10, is not used.

But the dynamic binding is. We need to declare the variable to be special:

? (let ((c 10))
    (declare (special c))
    (eval '(list 'a 'b c)))
(A B 10)

Thus this works, too:

? (let ((c 10))
    (declare (special c))
    (eval (read-from-string "`(a b ,c)")))
(A B 10)

Emacs Lisp had/has dynamic binding by default (though GNU Emacs now also supports lexical binding). Common Lisp has lexical binding by default.

like image 154
Rainer Joswig Avatar answered Sep 22 '22 14:09

Rainer Joswig