为什么arc中,(cons ‘a (cons 1 (cons “foo“ ‘(b) ))) 是(a 1 “foo“ b)
为什么arc中,(cons 'a (cons 1 (cons "foo" (cons '(b) nil)))) 是(a 1 "foo" (b)) 而(cons 'a (cons 1 (cons "foo" '(b) ))) 是(a 1 "foo" b)
在 Arc (以及 Lisp 家族的其他语言) 中,cons
函数用于创建序对,而序对是构建列表的基础。理解 cons
和列表之间的关系是关键。
理解 cons
cons
接受两个参数,并返回一个新的序对,其中第一个参数成为序对的 car
(也称为 first
),第二个参数成为序对的 cdr
(也称为 rest
)。
理解列表
列表本质上是一系列的嵌套序对,最后一个序对的 cdr
是 nil
。 nil
表示列表的结束。 (a b c)
实际上等价于 (cons 'a (cons 'b (cons 'c nil)))
。
分析第一个表达式:(cons 'a (cons 1 (cons "foo" (cons '(b) nil))))
(cons '(b) nil)
: 创建一个序对,car
是(b)
,cdr
是nil
。 这代表一个包含一个元素的列表(b)
。 注意这里(b)
本身是一个列表。(cons "foo" (cons '(b) nil))
: 创建一个序对,car
是"foo"
,cdr
是上面创建的列表(b)
。 这代表一个列表("foo" (b))
(cons 1 (cons "foo" (cons '(b) nil)))
: 创建一个序对,car
是1
,cdr
是上面创建的列表("foo" (b))
。 这代表一个列表(1 "foo" (b))
(cons 'a (cons 1 (cons "foo" (cons '(b) nil))))
: 创建一个序对,car
是'a
,cdr
是上面创建的列表(1 "foo" (b))
。 这代表一个列表(a 1 "foo" (b))
因此,整个表达式的结果是一个包含四个元素的列表,分别是 a
、1
、"foo"
和 (b)
,其中 (b)
也是一个列表。
分析第二个表达式:(cons 'a (cons 1 (cons "foo" '(b) )))
(cons "foo" '(b))
: 创建一个序对,car
是"foo"
,cdr
是列表(b)
。 这代表一个列表("foo" b)
。 关键在于'(b)
代表一个列表,等价于(cons 'b nil)
.(cons 1 (cons "foo" '(b)))
: 创建一个序对,car
是1
,cdr
是上面创建的列表("foo" b)
。 这代表一个列表(1 "foo" b)
(cons 'a (cons 1 (cons "foo" '(b) )))
: 创建一个序对,car
是'a
,cdr
是上面创建的列表(1 "foo" b)
。 这代表一个列表(a 1 "foo" b)
因此,整个表达式的结果是一个包含四个元素的列表,分别是 a
、1
、"foo"
和 b
。
关键区别:'(b)
vs (cons '(b) nil)
'(b)
: 这是一个简写形式,等价于(quote (b))
,直接表示一个包含单个元素b
的列表。b
被求值为符号b
。(cons '(b) nil)
: 显式地使用cons
来创建一个序对,其car
是列表(b)
,cdr
是nil
。这意味着(b)
本身是列表中的一个元素,而不是列表中的元素。
总结
关键的区别在于你如何构造列表以及如何使用 cons
。 第一个例子在列表的末尾添加了一个列表 (b)
作为元素,而第二个例子将 b
作为列表的一个普通元素添加到列表中。 '(b)
已经是一个列表。
好了,我们已经明白了原因,也就是cons的第二个参数要么是一个列表,要么是一个nil以便生成列表。这样(cons `(b) `(b))的结果就是((b) b)
有个更烧脑筋的是(cons `(b) 1) 输出结果是 ((b) . 1)
这是什么意思呢?意思就是cons的第二个参数既不是列表,也不是nil,那么它就创建了一个不规范的对,写成 (car . cdr)
叫作 dotted pair,也称作 cons cell。
为什么叫不规范对呢? 因为规范的是列表,列表的最后一个元素是nil,而形如列表,最后一个元素不是nil的,就叫对。让我们来看一下,它的cdr果然是一个数值:1
arc> (car (cons `(b) 1))
(b)
arc> (cdr (cons `(b) 1))
1