Quoting in Common Lisp

2019-02-15 14:06发布

I started to learn lisp recently. I was going over the examples in the book Land of Lisp and I felt that I was understanding everything rather well until I arrived to the following example around chapter 7:

(defun quote-it (x)
  (list 'quote x))

Now, I know that list would create a list with its arguments, like in (list 1 2 3 4) would evaluate to the list (1 2 3 4).

And I also know that quote allows me to quote an argument, pretty much like I can do with '. And so 'east is the same as (quote east)

Now, interestingly, the function above does not return a list, but simply quotes whatever I pass to it. And so, if I call it

(quote-it east) it would simply return 'east and not ('east)

If I had done this, I would have written the function as

(defun quote-it (x) 
  (quote x))

And so, I have no clue why we write the command as 'quote in (list 'quote x) in the example from the book.

I know I can switch between code and data by using quotes, like '(+ 1 2), but in this case it looks like my intention is to actually apply the quote function here. So, why (list 'quote x)?

So, can somebody out there with more experience clarify this?

4条回答
冷血范
2楼-- · 2019-02-15 14:27

You're being confused by the reader macro '.
Lisp's top level is read / eval / print if you read '(foo bar) you get (quote (foo bar)) if you eval (quote (foo bar)) you get (foo bar)

查看更多
我只想做你的唯一
3楼-- · 2019-02-15 14:29

Example: If you want to construct a list with a symbol foo and a variable number:

  • we have a number
  • we want to make a list (foo <some-number>)

Now we write a function for it:

(defun foo-it (n)
  (list 'foo n))

Obviously

(defun foo-it-1 (n)
  (foo n))

Won't work. It would call the function FOO on n instead of constructing a list.

(defun foo-it-2 (n)
  '(foo n))

Above would also not work, since the list (foo n) is not evaluated and returned as is.

Now Lisp has a backquote syntax:

(defun foo-it-3 (n)
  `(foo ,n))

Above will work. The comma marks that the symbol n will be evaluated.

For your problem. Replace foo with quote:

(list 'foo n)  ->   (list 'quote n)

or

`(foo ,n)    ->     `(quote ,n)

The main difference is that the Lisp printer will always print (foo 3) as (foo 3). FOO has no special purpose. But QUOTE has (because it is defined in the language) and the Lisp printer may print (quote 3) as '3.

Example:

CL-USER 14 > (progn
               (write (list 'foo 3) :pretty nil)
               (terpri)
               (write (list 'foo 3) :pretty t)
               (values))
(FOO 3)
(FOO 3)

CL-USER 15 > (progn
               (write (list 'quote 3) :pretty nil)
               (terpri)
               (write (list 'quote 3) :pretty t)
               (values))
(QUOTE 3)
'3

That's just because in Lisp, the quote character is defined built-in syntax and the printer knows about it.

Also note that printing is also modified by a set of special symbols like *print-pretty*, *print-readably*, .... So different Lisp setups might print different, based on the settings on those variables.

查看更多
再贱就再见
4楼-- · 2019-02-15 14:30

Lisp has lists, like: (mary threw the ball).

Some lists describe a computation, like: (* pi (+ r r))

That first list is data and the second is an expression suitable for the evaluator to chew on.

But we need a way to include data in expressions. So decades ago a special operator was introduced to enable that, like: (count-nouns (quote (mary threw the ball)))

Time passed and developers to tired of having to type (quote ...), so they invented a short hand notation: (count-nouns '(mary threw the ball)).

These days the shorthand is implemented at read time, as the characters are read out of the file or off the terminal. This is done with a facility know as "reader macros." This name confuses most beginners, since there is another facility in the language called "macros" which really has little if anything to do with reading the files. They are typically used to add a little syntactic sugar. As in this quote example. After the file (or terminal) stream has been read everything is just a list.

You will notice that if you enter: (quote bob) into your lisp prompt you will get back: 'bob. The printer is helpfully aware of the convention that (quote bob) has a shorthand form. If you ever decide to write your own reader macros you may want to teach the printer how to play along.

Macros, as v.s. reader macros, let you introduce your own special operators. And that lets you embed custom domain specific languages into your code. So - sort of - macros let you extend the semantics and reader macros let you extend the syntax. Macros effect the behavior of the compiler and the evaluator.

查看更多
我欲成王,谁敢阻挡
5楼-- · 2019-02-15 14:37

Lisp source code is represented by some of the same data structures that are used in Lisp programming. Of particular importance here are lists and symbols. When Lisp evaluates a form that has the form

(quote something)

that is to say, when Lisp evaluates a form which is a list and whose first element is the symbol quote, then it returns the object something without evaluating it. Thus

(quote 2)       ;=> 2
(quote (a b c)) ;=> (a b c)

Now, that's what the evaluator (or compiler, &c.) do when they get a Lisp object to evaluate that happens to be a list whose first element is the symbol quote. As Lisp programmers, we still have to write code for the Lisp reader to read and pass to the evalutor. We can write the long forms

(quote 2)
(quote (a b c))

in our source, and the Lisp reader will read them and pass them to the compiler, but we're virtuous programmers, so we're lazy, and want to avoid some typing. So, we can type

'2
'(a b c)

instead. The compiler ends up getting exactly the same input; a list whose first element is the symbol quote and whose second value is 2 or (a b c).

Now we can talk about your code. The form

(list 'quote x)

returns a list whose first element is the symbol quote, and whose second element is the value of the variable x. That can be printed as

(quote <value-of-x>) ; fill in x's value for <value-of-x>, of course

Now, the Lisp printer is a bit clever, and has the option of printing things like that using the same shorthand that we're allowed to use when we're writing source. So that can also be printed as

'<value-of-x>

Now we've got enough to address your question about the book's code:

Now, interestingly, the function above does not return a list, but simply quotes whatever I pass to it. And so, if I call it

(quote-it east) it would simply return 'east and not ('east)

Since 'east is an abbreviation for (quote east), we now see that (quote-it east) does, in fact, return a list. And it's a list of the form you'd expect: a list whose first element is the symbol quote and whose second element is the symbol east. If it had returned ('east), it would still be returning a list, but it would be returning a list of the wrong form. ('east) is, when we expand the abbreviation, the list ((quote east)); that is, it's a list of a single element, and that element is another list whose first element is the symbol quote and whose second element is the symbol east. It's certainly a list, but it's not the list you were looking for.

Now we can take a look at your proposed code. Your function quote-it only incidentally happens to work in the case that you're calling (quote-it 'x). That is, you can do

(quote-it 'x)
;=> x

but notice that you're getting a symbol back, and you're getting the symbol x back. You're not getting a list whose first element is the symbol quote and whose second element is <value-of-x>. When you use quote-it with other values, you'll see the problem:

(quote-it 2)
;=> x

You still get a symbol back, because

(defun quote-it (x) 
  (quote x))         ; or 'x

Takes an argument, binds it to the lexical variable x, and then returns the value of (quote x). What's the value of (quote x)? As explained earlier, when the evaluator (or compiler, &c.) gets a list of the symbol quote and something, the value is the literal something. Since the body of quote-it is a list of the symbol quote and the symbol x, the value of the body of quote-it is the symbol x.

查看更多
登录 后发表回答