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
),因此结果是一个列表,以list
或quote
符号开头。这是让我困惑的第四个问题。为什么不返回(QUOTE (1 2 3))
?
我意识到如果你在REPL中输入(QUOTE '(1 2 3))
,你会得到'(1 2 3)
,所以表达式在这个意义上是等价的。但是(LIST 1 2 3)
相当于(1 2 3)
,但第一个表达式并没有返回。
(list 'quote 1 2 3)
返回一个第一项为quote
符号的列表似乎不一致,但(list 'quote (1 2 3))
会返回引用列表。特别是因为像(list 'list ...)
这样的表达似乎总是返回一个以符号开头的列表 - 到目前为止,至少quote
是唯一的特殊情况'像这样。
这不是最容易表达的问题,所以我希望我能够解决这个问题。任何人都可以解释为什么报价会以这种看似独特的方式得到对待吗?
答案 0 :(得分:5)
'something
与(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
。然而,读者可以阅读这些中的任何一个,并且它们将全部打印相同的例如。 '(1 . (2 . (3 . ()))) ==> (1 2 3)
和(+ . (2 . ( 3 . ()))) ; ==> 5
数字可以包含与所讨论数字之下的基数一样多的视觉形式。
(let ((*print-base* 16))
(print 255)) ; prints FF (255 in hexadecimal)
list
在Lisp中没有任何缩写或特殊性。它甚至不是一个原始的功能,但它非常有用,因为它消除了每次必须手工使用的不便。它可以这样定义:
(defun my-list (&rest lst)
lst)
(my-list 1 2 3 4) ; ==> (1 2 3 4)
答案 1 :(得分:3)
请注意,REPL(READ-EVAL-PRINT-LOOP)有三件事:
READ
EVAL
PRINT
要了解发生了什么,你必须查看所有三个功能。
让我们看一下第三种形式:
(list 'quote 1 2 3)
这是一个包含五个要素的列表:
LIST
(QUOTE QUOTE)
1
2
3
EVAL
然后计算参数,并使用四个结果调用函数list
并返回一个新结果,一个包含四个元素的列表:
QUOTE
1
2
3
PRINT
然后获取此列表并将其写为:(QUOTE 1 2 3)
。没有缩写的方式来打印它。
让我们看看第四种形式:
(list 'quote '(1 2 3))
这被视为三个元素的列表:
LIST
(QUOTE QUOTE)
(QUOTE (1 2 3))
eval
使用两个参数调用list
:
QUOTE
(1 2 3)
eval
然后返回长度为二的列表:
QUOTE
(1 2 3)
print
现在可以通过两种不同的方式打印此列表:
(QUOTE (1 2 3))
或缩写形式'(1 2 3)
。这里引号字符位于单个表达式的前面。
您的实施使用了第一个版本。