我听说clojure在大多数lisp语言中都没有 cons cells 。
这是否意味着clojure列表不以空列表结尾?
任何人都可以解释这究竟意味着什么吗?
答案 0 :(得分:24)
Lisp提供原始的cons数据结构及其符号。
该章介绍:
( a . b )
(a b c)
nil
car
,cdr
,cons
,eq
和atom
ff
,subst
,equal
,null
,cadr
,caddr
,null
,{ {1}},append
,among
,pair
,assoc
,sublis
,apply
,... 在Lisp的早期,添加了改变cons单元格的函数:eval
(表示替换汽车)和rplaca
(表示替换cdr )。请参阅LISP 1.5 Programmer's Manual by John McCarthy et al. from 1962。这些函数允许我们编写破坏性函数,并允许我们创建循环的基于cons的数据结构,如循环列表。
Common Lisp
通常,Lisp方言实现了大部分内容。 Common Lisp也不例外,Common Lisp标准中描述了这个功能:Conses。使用上述功能的示例:
rplacd
列表是符号表达式的特例。它们通常没有点写:
; pair two lists into a list of cons cells
; the function pair is called pairlis in Common Lisp
CL-USER 17 > (pairlis '(john mary eva) `(34 29 40))
((EVA . 40) (MARY . 29) (JOHN . 34))
; find a cons cell in a list of cons cells, based on the content of the car of those cons cells
CL-USER 18 > (assoc 'eva
(pairlis '(john mary eva)
`(34 29 40)))
(EVA . 40)
; create a tree out of cons cells and atoms
CL-USER 19 > (cons (cons 10 20) (cons 30 40))
((10 . 20) 30 . 40)
; a cons cell is not an atom
CL-USER 20 > (atom (cons 1 2))
NIL
; a cons cell is not nil
CL-USER 21 > (null (cons 1 2))
NIL
; substitute an item with a new one in a tree
CL-USER 22 > (subst 30 ; new
'bar ; old
'((10 . 20) . (bar . 40))) ; tree
((10 . 20) 30 . 40) ; also written as ((10 . 20) . (30 . 40))
; substitute several items in a tree, using an assoc list
; to describe the substitutions
CL-USER 23 > (sublis '((a . 10) (d . 40)) ; substitutions
'((a . b) . (c . d))) ; tree
((10 . B) C . 40)
Common Lisp还支持Lisp 1.5的变异操作CL-USER 24 > '(a . (b . nil))
(A B)
和rplaca
:
rplacd
Emacs Lisp
Emacs Lisp还实现了上述功能:
CL-USER 25 > (let ((c (cons 0 1))) ; create a cons
(print c) ; print it
(print (rplaca c 'foo)) ; replace the car
(print (rplacd c 'bar)) ; replace the cdr
(print (eq c (rplaca c 'baz))) ; identical ?
(values))
(0 . 1) ; the cons cell
(FOO . 1) ; car replaced
(FOO . BAR) ; cdr replaced
T ; still the same object
<强> Clojure的强>
Clojure 不支持John McCarthy所描述的这些符号表达式。它没有缺陷单元,没有点符号,也没有提供上述接口。例如, atom 意味着Clojure中完全不同的东西。 ELISP> (sublis '((a . 10) (d . 40))
'((a . b) . (c . d)))
((10 . b) c . 40)
不会创建一个cons小区。列表不是由缺陷单元组成的。
在Clojure中,一个点只是另一个符号:
cons
有一个原始函数来构造列表:
user=> (count '(1 . 2))
3
结果应该是一个列表:
user=> (list 1 2 3)
(1 2 3)
有一个名为user=> (list? (list 1 2 3))
true
的函数:
cons
不知道这不是一个清单:
user=> (cons 0 (list 1 2 3))
(0 1 2 3)
基本上Clojure使用不同的数据结构( - &gt; sequences,逻辑列表)和自己的命名和语义。即使姓名与Lisp名称相似,也不要期望他们也这样做。
<强>方案强>
编程语言 Scheme 还提供类似于上面的缺点单元。它缺少一些功能,但可以很容易地实现。例如,user=> (list? (cons 0 (list 1 2 3)))
false
可能在Scheme中实现(请参阅initdr.scm):
sublis
答案 1 :(得分:7)
clojure.lang.Cons
。cons
来电rest
/ cdr
是一个序列,而不是Object
。cons
列表,矢量或懒惰序列,
你得到一个Cons
。Cons
es。它们都是按顺序处理的。 另一个用途:conj
到一个不确定的序列(矢量列表,既不设置也不映射......)产生Cons
。
答案 2 :(得分:6)
缺点,第一次和休息操纵序列抽象,而不是具体的缺点
Clojure列表不以空列表结尾,它们不是传统的cons单元格。它们是实现排序的数据结构。 This page on programming to abstractions解释了Clojure对&#34; seqable&#34;的解决方法。结构,包括清单:
通常,对抽象的编程可以让您在不同的数据结构上使用函数库,而不管这些数据结构是如何实现的。
所以Clojure列表就像cons单元格一样,它们实现cons
,first
和rest
但这只意味着它们共享一个公共接口。它们的底层实现有所不同,但它们都是“可以选择的”#34;。
答案 3 :(得分:1)
在Common Lisp中,列表是一系列缺点单元格。每个cons单元有两个槽或指针,称为“car”和“cdr”。汽车指向(或持有)某物 - 任何东西。 cdr通常指向另一个cons单元格,或nil
。 nil
计为列表的末尾。 Clojure为其提供了与其列表大致相同的功能,但底层表示是不同的。它确实有一个名为Cons
的数据类型,但并非所有列表或给定列表的所有部分都是从Cons
构建的。 (现在你应该阅读jmargolisvt的答案,如果你还没有。)[编辑:其他答案显示我在这里所说的关于Clojure中列表和Conses之间关系的说法是错误的。人们可能会觉得这是非正式的“列表” - 或者没有。“
另请注意,部分由于序列抽象概念,列表本身在Clojure中比在Common Lisp或Scheme中少得多。但是,其他类型的序列非常常见。
同样值得一提的是,在Clojure中你不能假设当你打印它时看起来像列表的东西实际上是一个列表。例如,它可能是一个惰性序列,不被认为是列表。
以下是使用列表的一些可能提供信息的Clojure示例:
user=> (def foo (list 1))
#'user/foo
user=> foo
(1)
user=> (class foo)
clojure.lang.PersistentList
user=> (def bar (cons 2 foo))
#'user/bar
user=> bar
(2 1)
user=> (class bar)
clojure.lang.Cons
(foo
和bar
都被视为列表,即使class
返回不同的数据类型。)
user=> (next bar)
(1)
user=> (rest bar)
(1)
user=> (class (next bar))
clojure.lang.PersistentList
user=> (class (rest bar))
clojure.lang.PersistentList
user=> (next foo)
nil
user=> (rest foo)
()
user=> (= nil ())
false
user=> (rest ())
()
user=> (rest nil)
()
user=> (next ())
nil
user=> (next nil)
nil
在Common Lisp中,您可以将对象包含在列表或nil
以外的其他对象上。结果是一个“点列表”(1 . 2)
,它是一个单一的cons单元格,其中cdr指针指向除了另一个cons单元格或nil
之外的其他内容,就像在普通列表中一样。让我们在Clojure中尝试一下:
user=> (cons 1 2)
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:528)
虽然我很喜欢它,但是与Common Lisp(其中nil
= ()
= false)有一个显着的区别:
user=> (= nil false)
false
user=> (= () false)
false
但是,即使nil
不是false
,您也可以像false
一样使用它:
user=> (if nil "nil works like true" "nil works like false")
"nil works like false"
但是,您无法使用空列表执行此操作:
user=> (if () "() works like true" "() works like false")
"() works like true"
(尽管有这些例子,整个Clojure比Common Lisp,IMO更简单,更优雅。即使是喜欢Common Lisp的人 - 就像我一样 - 必须承认Common Lisp既不简单也不优雅。有自己的美丽。)