When to use ' (or quote) in Lisp?

2019-01-02 22:15发布

After making it through the major parts of an introductory Lisp book, I still couldn't understand what the special operator (quote) (or equivalent ') function does, yet this has been all over Lisp code that I've seen.

What does it do?

标签: lisp quote
9条回答
Root(大扎)
2楼-- · 2019-01-02 22:27

Anoter short answer:

quote means without evaluating it, and backquote is quote but leave back doors.

A good referrence:

Emacs Lisp Reference Manual make it very clear

9.3 Quoting

The special form quote returns its single argument, as written, without evaluating it. This provides a way to include constant symbols and lists, which are not self-evaluating objects, in a program. (It is not necessary to quote self-evaluating objects such as numbers, strings, and vectors.)

Special Form: quote object

This special form returns object, without evaluating it. 

Because quote is used so often in programs, Lisp provides a convenient read syntax for it. An apostrophe character (‘'’) followed by a Lisp object (in read syntax) expands to a list whose first element is quote, and whose second element is the object. Thus, the read syntax 'x is an abbreviation for (quote x).

Here are some examples of expressions that use quote:

(quote (+ 1 2))
     ⇒ (+ 1 2)

(quote foo)
     ⇒ foo

'foo
     ⇒ foo

''foo
     ⇒ (quote foo)

'(quote foo)
     ⇒ (quote foo)

9.4 Backquote

Backquote constructs allow you to quote a list, but selectively evaluate elements of that list. In the simplest case, it is identical to the special form quote (described in the previous section; see Quoting). For example, these two forms yield identical results:

`(a list of (+ 2 3) elements)
     ⇒ (a list of (+ 2 3) elements)

'(a list of (+ 2 3) elements)
     ⇒ (a list of (+ 2 3) elements)

The special marker ‘,’ inside of the argument to backquote indicates a value that isn’t constant. The Emacs Lisp evaluator evaluates the argument of ‘,’, and puts the value in the list structure:

`(a list of ,(+ 2 3) elements)
     ⇒ (a list of 5 elements)

Substitution with ‘,’ is allowed at deeper levels of the list structure also. For example:

`(1 2 (3 ,(+ 4 5)))
     ⇒ (1 2 (3 9))

You can also splice an evaluated value into the resulting list, using the special marker ‘,@’. The elements of the spliced list become elements at the same level as the other elements of the resulting list. The equivalent code without using ‘`’ is often unreadable. Here are some examples:

(setq some-list '(2 3))
     ⇒ (2 3)

(cons 1 (append some-list '(4) some-list))
     ⇒ (1 2 3 4 2 3)

`(1 ,@some-list 4 ,@some-list)
     ⇒ (1 2 3 4 2 3)
查看更多
神经病院院长
3楼-- · 2019-01-02 22:29

In Emacs Lisp:

What can be quoted ?

Lists and symbols.

Quoting a number evaluates to the number itself: '5 is the same as 5.

What happens when you quote lists ?

For example:

'(one two) evaluates to

(list 'one 'two) which evaluates to

(list (intern "one") (intern ("two"))).

(intern "one") creates a symbol named "one" and stores it in a "central" hash-map, so anytime you say 'one then the symbol named "one" will be looked up in that central hash-map.

But what is a symbol ?

For example, in OO-languages (Java/Javascript/Python) a symbol could be represented as an object that has a name field, which is the symbol's name like "one" above, and data and/or code can be associated with it this object.

So an symbol in Python could be implemented as:

class Symbol:
   def __init__(self,name,code,value):
       self.name=name
       self.code=code
       self.value=value

In Emacs Lisp for example a symbol can have 1) data associated with it AND (at the same time - for the same symbol) 2) code associated with it - depending on the context, either the data or the code gets called.

For example, in Elisp:

(progn
  (fset 'add '+ )
  (set 'add 2)
  (add add add)
)

evaluates to 4.

Because (add add add) evaluates as:

(add add add)
(+ add add)
(+ 2 add)
(+ 2 2)
4

So, for example, using the Symbol class we defined in Python above, this add ELisp-Symbol could be written in Python as Symbol("add",(lambda x,y: x+y),2).

Many thanks for folks on IRC #emacs for explaining symbols and quotes to me.

查看更多
对你真心纯属浪费
4楼-- · 2019-01-02 22:34

Short answer Bypass the default evaluation rules and do not evaluate the expression (symbol or s-exp), passing it along to the function exactly as typed.

Long Answer: The Default Evaluation Rule

When a regular (I'll come to that later) function is invoked, all arguments passed to it are evaluated. This means you can write this:

(* (+ a 2)
   3)

Which in turn evaluates (+ a 2), by evaluating a and 2. The value of the symbol a is looked up in the current variable binding set, and then replaced. Say a is currently bound to the value 3:

(let ((a 3))
  (* (+ a 2)
     3))

We'd get (+ 3 2), + is then invoked on 3 and 2 yielding 5. Our original form is now (* 5 3) yielding 15.

Explain quote Already!

Alright. As seen above, all arguments to a function are evaluated, so if you would like to pass the symbol a and not its value, you don't want to evaluate it. Lisp symbols can double both as their values, and markers where you in other languages would have used strings, such as keys to hash tables.

This is where quote comes in. Say you want to plot resource allocations from a Python application, but rather do the plotting in Lisp. Have your Python app do something like this:

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

Giving you output looking like this (slightly prettyfied):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

Remember what I said about quote ("tick") causing the default rule not to apply? Good. What would otherwise happen is that the values of allocate and free are looked up, and we don't want that. In our Lisp, we wish to do:

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

For the data given above, the following sequence of function calls would have been made:

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

But What About list?

Well, sometimes you do want to evaluate the arguments. Say you have a nifty function manipulating a number and a string and returning a list of the resulting ... things. Let's make a false start:

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

Hey! That's not what we wanted. We want to selectively evaluate some arguments, and leave the others as symbols. Try #2!

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

Not Just quote, But backquote

Much better! Incidently, this pattern is so common in (mostly) macros, that there is special syntax for doing just that. The backquote:

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

It's like using quote, but with the option to explicitly evaluate some arguments by prefixing them with comma. The result is equivalent to using list, but if you're generating code from a macro you often only want to evaluate small parts of the code returned, so the backquote is more suited. For shorter lists, list can be more readable.

Hey, You Forgot About quote!

So, where does this leave us? Oh right, what does quote actually do? It simply returns its argument(s) unevaluated! Remember what I said in the beginning about regular functions? Turns out that some operators/functions need to not evaluate their arguments. Such as IF -- you wouldn't want the else branch to be evaluated if it wasn't taken, right? So-called special operators, together with macros, work like that. Special operators are also the "axiom" of the language -- minimal set of rules -- upon which you can implement the rest of Lisp by combining them together in different ways.

Back to quote, though:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

Compare to (on Steel-Bank Common Lisp):

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING   {A69F6A9}>:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0] 

Because there is no spiffy-symbol in the current scope!

Summing Up

quote, backquote (with comma), and list are some of the tools you use to create lists, that are not only lists of values, but as you seen can be used as lightweight (no need to define a struct) data structures!

If you wish to learn more, I recommend Peter Seibel's book Practical Common Lisp for a practical approach to learning Lisp, if you're already into programming at large. Eventually on your Lisp journey, you'll start using packages too. Ron Garret's The Idiot's Guide to Common Lisp Packages will give you good explanation of those.

Happy hacking!

查看更多
我只想做你的唯一
5楼-- · 2019-01-02 22:38

Quote returns the internal representation of its arguments. After plowing through way too many explanations of what quote doesn't do, that's when the light-bulb went on. If the REPL didn't convert function names to UPPER-CASE when I quoted them, it might not have dawned on me.

So. Ordinary Lisp functions convert their arguments into an internal representation, evaluate the arguments, and apply the function. Quote converts its arguments to an internal representation, and just returns that. Technically it's correct to say that quote says, "don't evaluate", but when I was trying to understand what it did, telling me what it doesn't do was frustrating. My toaster doesn't evaluate Lisp functions either; but that's not how you explain what a toaster does.

查看更多
Bombasti
6楼-- · 2019-01-02 22:46

When we want to pass an argument itself instead of passing the value of the argument then we use quote. It is mostly related to the procedure passing during using lists, pairs and atoms which are not available in C programming Language ( most people start programming using C programming, Hence we get confused) This is code in Scheme programming language which is a dialect of lisp and I guess you can understand this code.

(define atom?              ; defining a procedure atom?
  (lambda (x)              ; which as one argument x
(and (not (null? x)) (not(pair? x) )))) ; checks if the argument is atom or not
(atom? '(a b c)) ; since it is a list it is false #f

The last line (atom? 'abc) is passing abc as it is to the procedure to check if abc is an atom or not, but when you pass(atom? abc) then it checks for the value of abc and passses the value to it. Since, we haven't provided any value to it

查看更多
Ridiculous、
7楼-- · 2019-01-02 22:47

It says "don't evaluate me". For example, if you wanted to use a list as data, and not as code, you'd put a quote in front of it. For example,

(print '(+ 3 4)) prints "(+ 3 4)", whereas (print (+ 3 4)) prints "7"

查看更多
登录 后发表回答