LISP 中引号的表观 'eval'

Apparent 'eval' of quote symbol in CLISP

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)

前三个,我完全明白是怎么回事:list函数被传递了一个符号('list'quote),所以结果是一个以以下开头的列表listquote 符号。这是第四个让我困惑的。为什么不 return (QUOTE (1 2 3))?

我意识到如果你在 REPL 中输入 (QUOTE '(1 2 3)),你会得到 '(1 2 3),所以从这个意义上说,表达式是等价的。但是 (LIST 1 2 3) 等同于 (1 2 3),但第一个表达式并不 return 那个。

似乎不​​一致 (list 'quote 1 2 3) return 是第一项是 quote 符号的列表,但 (list 'quote (1 2 3)) return 是引用列表。特别是因为像 (list 'list ...) 这样的表达式似乎总是 return 以符号开头的列表 - 到目前为止,至少,quote 是唯一的 'special case' 这样的。

这不是最容易表达的问题,所以我希望我已经设法解决了我的困惑。谁能解释为什么报价会以这种看似独特的方式处理?

'something 与 lisp reader 的 (quote something) 相同。即使嵌套也会如此。我将在下一个表达式中加双引号,以便在评估后其中一个引号仍然存在。

当打印实现时,可以选择在有几种可能表示的情况下输出什么,因此一些实现会将 ''something 的评估打印为 (quote something) 而其他人可能会使用缩写 'something.

'(quote 1 2 3) 不能缩写,因为引用形式只有一个参数。因此这里两个 lisp 系统都会打印 (quote 1 2 3).

这是查看您最后一个表情的方法:

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

这将计算为 "whole thing: '(1 2 3) first element: QUOTE second-element: (1 2 3)""whole thing: (QUOTE (1 2 3)) first element: QUOTE second-element: (1 2 3)"

由于打印机永远不会看到输入是否被缩写,并且数据在内存中具有相同的结构,因此输出永远不会受到您输入数据的方式的影响。因此 (quote (quote (1 2 3))) 将打印与 ''(1 2 3).

相同的内容

您对 cons 个单元格有相同的行为,但标准规定了规则。 (cons 1 (cons 2 (cons 3 '()))) 将是 (1 . (2 . (3 . ()))) 但实际上只是打印 (1 2 3) 但是,如果你 (cons 1 2) 你会得到 (1 . 2) 表明 print 以不同的方式处理输出cdr。但是 reader 可以读取其中任何一个,并且它们都将打印相同的内容,例如。 '(1 . (2 . (3 . ()))) ==> (1 2 3)(+ . (2 . ( 3 . ()))) ; ==> 5

数字可以有与相关数字下方的碱基一样多的视觉形式。

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

list 在 Lisp 中没有任何缩写或特殊性。它甚至不是一个原始函数,但它非常有用,因为它消除了每次都必须手动进行 cons 的不便。可以这样定义:

(defun my-list (&rest lst)
  lst)

(my-list 1 2 3 4) ; ==> (1 2 3 4)

请注意,REPL(READ-EVAL-PRINT-LOOP)会做三件事:

  • 使用函数读取READ
  • 使用函数求值EVAL
  • 并使用函数 PRINT
  • 之类的东西打印结果

要了解发生了什么,您必须查看所有三个函数。

再来看第三种形式:

(list 'quote 1 2 3)

这是一个包含五个元素的列表:

  1. LIST
  2. (QUOTE QUOTE)
  3. 1
  4. 2
  5. 3

EVAL 然后计算参数,并用四个结果调用函数 list 和 returns 一个新结果,一个包含四个元素的列表:

  1. QUOTE
  2. 1
  3. 2
  4. 3

PRINT 然后把这个列表写成:(QUOTE 1 2 3)。没有简化的打印方式。

我们来看第四种形式:

(list 'quote '(1 2 3))

这被读取为三个元素的列表:

  1. LIST
  2. (QUOTE QUOTE)
  3. (QUOTE (1 2 3))

eval 使用两个参数调用 list

  1. QUOTE
  2. (1 2 3)

eval 然后 returns 长度为二的列表:

  1. QUOTE
  2. (1 2 3)

print 现在可以用两种不同的方式打印此列表:

(QUOTE (1 2 3)) 或缩写形式 '(1 2 3)。这里一个引号字符在单个表达式的前面。

您的实现使用了第一个版本。