help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How the backquote and the comma really work?


From: sokobania . 01
Subject: Re: How the backquote and the comma really work?
Date: Tue, 30 Jun 2015 09:27:45 -0700 (PDT)
User-agent: G2/1.0

Le jeudi 25 juin 2015 19:09:31 UTC+2, Marcin Borkowski a écrit :
> Hi all,
> 
> I decided that the time has come that I finally approach the scary
> backquote-comma duo.  (While I understand it superficially, I'd like to
> get it right and thoroughly this time.)  So my question is whether my
> mental model (see below) is correct.

I made the same decision... long time ago...
Before backquote, I first needed to be clear with "quote" and "eval".
When I fully understood the "'foo" "foo" "(eval 'foo)" "(eval foo)",
I could go for the backquote thing.

I would suggest to read some documentation like:
http://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote.html
http://www.cs.cmu.edu/cgi-bin/info2www?(elisp)Backquote

> So, I assume that when Emacs Lisp interpreter encounters a backquote, it
> looks at the expression after it.  If it is anything but a list, it just
> works like the usual quote, and the backquoted expression evaluates to
> what was backquoted.
> 
> If it is a list, its element are read

as already mentioned, they were read by the reader long time 
before being parsed by the backquote macro itself!

> Michael Heerdegen wrote:
>> Of course, the elements have already been read by the reader.

> and scanned.  If any part of the
> list (probably a nested one) begins with a comma, the whole thing after
> the comma (be it a symbol, a list or whatever) is evaluated as usual,
> and the result is put into the resulting list.

Well... more or less...

The backquote process itself does NOT evaluate anything.
It is better to think of it in terms of expansion.
The evaluation comes AFTER the backquote has expanded its stuff.

When I need to evaluate more than 1 or 2 expressions, i use "M-x ielm"
so that I can see all the results, copy/paste them, etc.

Here, I'll use "print" so that you see both the real thing first
and the way it's pretty-printed in a more human-readable way.

ELISP> (print (read "`',foo"))
(\` (quote (\, foo)))
`',foo

ELISP> (print (macroexpand ''foo))
(quote foo)
'foo

ELISP> (print (macroexpand '`',foo))
(list (quote quote) foo)
(list 'quote foo)

ELISP> (print (macroexpand '`(a ,b c)))
(cons (quote a) (cons b (quote (c))))
(cons 'a
      (cons b
            '(c)))

In this last example, you can see that `(a ,b c) 
is very close to (list 'a b 'c)
where the function "list" evaluates its arguments:
- 'a evaluates to the symbol "a"
- b evaluates to the symbol-value of the symbol "b"
- 'c evaluates to the symbol "c"
and "list" returns a new list with the these values.

> Whew.  Is that (more or less) right?

Yes! (more or less)

> can I find an Emacs Lisp metacircular evaluator (taking
> into account the quoting mechanisms) anywhere?

You can have a look at 
https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node367.html

(defun bq-process (x) 
  (cond ((atom x) 
         (list *bq-quote* x)) 
        ((eq (car x) 'backquote) 
         (bq-process (bq-completely-process (cadr x)))) 
        ((eq (car x) *comma*) (cadr x))   ;; <---
        ((eq (car x) *comma-atsign*) 
         (error ",@~S after `" (cadr x))) 
        ((eq (car x) *comma-dot*) 
         (error ",.~S after `" (cadr x))) 
        (t (do ((p x (cdr p)) 
                (q '() (cons (bracket (car p)) q))) 
               ((atom p) 
                (cons *bq-append* 
                      (nreconc q (list (list *bq-quote* p))))) 
             (when (eq (car p) *comma*) 
               (unless (null (cddr p)) (error "Malformed ,~S" p)) 
               (return (cons *bq-append* 
                             (nreconc q (list (cadr p)))))) 
             (when (eq (car p) *comma-atsign*) 
               (error "Dotted ,@~S" p)) 
             (when (eq (car p) *comma-dot*) 
               (error "Dotted ,.~S" p))))))

(remember that ",xx" has already been expanded into "(, xx)",
which is a list with 2 items, the symbol "," and "xx")
On the 6th line, you can see that if "x" is a list beginning with a comma,
the backquote-process just returns whatever is in the 2nd position of this list.

> And I know that I risk starting another thread lasting for dozens of
> messages;-) - but I /do/ want to understand this stuff...  In fact, in
> the spirit of another recent discussion, I want to write a simple code
> analyzer, finding one-legged 'if's and suggesting replacing them with
> 'when's or 'unless'es.

Good idea!

>  This is trivial unless (pun intended) you want
> to take (back)quotes into consideration.

You probably don't want to rewrite a reader!
I would suggest that you "just" write a parser, something like:
(until (eof)
  (parse (read)))

So, you must be very clear with what you'll get from the reader.
Remember the "read" process skips comments and 
"recognizes/creates" a lot of stuff,
like strings, symbols, numbers, lists, etc.

During this process, the macro characters have already been expanded:
"`xx" -> "(`xx)"
but the macro function "`" has NOT been expanded yet.

Maybe your code could force the expansion:
(until (eof)
  (parse (macroexpand (read))))

HTH
)jack(


reply via email to

[Prev in Thread] Current Thread [Next in Thread]