Search code examples
lispcommon-lispclisp

Apparent 'eval' of quote symbol in CLISP


Some output from the CLISP REPL:

[1]> (list 'list 1 2 3)
(LIST 1 2 3)

[2]> (list 'list '(1 2 3))
(LIST (1 2 3))

[3]> (list 'quote 1 2 3)
(QUOTE 1 2 3)

[4]> (list 'quote '(1 2 3))
'(1 2 3)

The first three, I understand exactly what's going on: The list function is passed a symbol ('list or 'quote) and so the result is a list that begins with the list or quote symbol. It's the fourth that confuses me. Why doesn't it return (QUOTE (1 2 3))?

I realise that if you enter (QUOTE '(1 2 3)) into the REPL, you get '(1 2 3) back, so the expression are equivalent in that sense. But (LIST 1 2 3) is equivalent to (1 2 3), and yet the first expression doesn't return that.

It seems inconsitent that (list 'quote 1 2 3) returns a list with the first item being a quote symbol, but (list 'quote (1 2 3)) returns a quoted list. Especially since expressions like (list 'list ...) seem to always return a list beginning with the symbol - so far, at least, quote is the only 'special case' like this.

It's not the easiest question to articulate, so I'm hoping I've managed to get my confusion across. Can anyone explain why quote gets treated in this seemingly-unique way?


Solution

  • 'something is the same as (quote something) for the lisp reader. Even when nested it will be the case. The next expressions I will double quote so that after evaluation one of the quotes are still in there.

    When printing the implementations can choose what to output where there are several possible representations, so some implementations would print the evaluation of ''something as (quote something) while others may use the abbreviation 'something.

    '(quote 1 2 3) cannot be abbreviated since a quoted form only has one argument. Thus here both lisp systems would print (quote 1 2 3).

    Here is a way to look at your last expression:

    (let ((data (list 'quote '(1 2 3))))
      (format nil 
              "whole thing: ~a first element: ~a second-element: ~a" 
              data 
              (car data) 
              (cadr data)))
    

    This will either evaluate to "whole thing: '(1 2 3) first element: QUOTE second-element: (1 2 3)" or "whole thing: (QUOTE (1 2 3)) first element: QUOTE second-element: (1 2 3)".

    Since the printer never sees if the input is abbreviated and the data has the same structure in memory the output is never affected by how you input the data. Thus (quote (quote (1 2 3))) will print the same as ''(1 2 3).

    You have the same behaviour with cons cells but the standard dictates how the rules are. (cons 1 (cons 2 (cons 3 '()))) would be (1 . (2 . (3 . ()))) but is actually just printed (1 2 3) However if you (cons 1 2) you get (1 . 2) showing that print treats the output differently based on the cdr. However the reader can read any of these and they will all print the same eg. '(1 . (2 . (3 . ()))) ==> (1 2 3) and (+ . (2 . ( 3 . ()))) ; ==> 5

    Numbers can have as many visual forms as there are bases below the number in question.

    (let ((*print-base* 16))
      (print 255)) ; prints FF (255 in hexadecimal)
    

    list does not have any abbreviation or specialness in Lisp. It's not even a primitive function but it's very helpful as it removes the inconvenience of having to cons by hand everytime. It can be defined like this:

    (defun my-list (&rest lst)
      lst)
    
    (my-list 1 2 3 4) ; ==> (1 2 3 4)