Clojure:缺点(seq)与缺点(清单)


98

我知道这会cons返回一个seq并conj返回一个集合。我也知道,conj将项目“添加”到集合的最佳末端,并且cons始终将其“添加”到最前面。此示例说明了以下两点:

user=> (conj [1 2 3] 4) ; returns a collection
[1 2 3 4]
user=> (cons 4 [1 2 3]) ; returns a seq
(4 1 2 3)

对于矢量,地图和集合,这些差异对我来说很有意义。但是,对于列表,它们似乎相同。

user=> (conj (list 3 2 1) 4) ; returns a list
(4 3 2 1)
user=> (cons 4 (list 3 2 1)) ; returns a seq
(4 3 2 1)

是否有使用列表的示例,其中conjvs. cons表现出不同的行为,或者它们是否真正可互换?用不同的措词,是否有一个示例,其中列表和seq不能等效使用?

Answers:


150

一个区别是conj接受任意数量的参数以插入到集合中,而cons只接受一个:

(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)

(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity

另一个区别在于返回值的类别:

(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList

(class (cons 4 '(1 2 3))
; => clojure.lang.Cons

注意,这些并不是真正可以互换的。特别clojure.lang.Cons是不会实现clojure.lang.Counted,因此a count不再是固定时间的操作(在这种情况下,它可能会减少为1 + 3 - 1来自第一个元素的线性遍历,3来自(next (cons 4 '(1 2 3))a PersistentList和因此Counted)。

我认为,名称背后的cons意思是cons(构成一个seq)1,而conjconj(将一个项目包含在一个集合中)。由seq构造的cons开始于将元素作为第一个参数传递,并将next/ rest应用于seq第二个参数所产生的事物作为其一部分。如上所示,整个东西都是类clojure.lang.Cons。相反,conj始终返回与传递给它的集合大致相同类型的集合。(大致来说,因为a 超过9个条目PersistentArrayMap就会立即变成a PersistentHashMap。)


1传统上,在Lisp世界中,conscons(构造成对),所以Clojure偏离Lisp传统,因为其cons功能构造了一个没有传统的seq cdrcons在编程语言及其实现的研究中,普遍使用的含义是“构造某种类型的记录或将其他值保存在一起的其他记录”。这就是提到“避免打扰”的意思。


1
太棒了!我没有意识到有一个Cons类型。做得好!
Daniel Yankowsky 2010年

谢谢。高兴听到。:-)
米哈尔Marczyk

2
顺便说一句,作为一种特殊情况,(cons foo nil)返回单例PersistentList(同样对于conj)。
米哈尔Marczyk

1
另一个极好的解释。你真的是个clojure绝地武士!
dbyrne 2010年

1
以我的经验,当性能很重要时,将列表视为列表而不是顺序很重要。
cgrand 2010年

11

我的理解是您所说的是对的:列表上的conj等同于列表上的cons。

您可以将conj看作是“在某处插入”操作,而将cons看作是在“头插入”操作。在列表上,最合乎逻辑的是插入到头部,因此conj和cons在这种情况下是等效的。


8

另一个区别是,由于conj将序列作为第一个参数,因此alter在将a更新ref为某些序列时可以很好地发挥作用:

(dosync (alter a-sequence-ref conj an-item))

这基本上(conj a-sequence-ref an-item)是以线程安全的方式进行的。这不适用于cons。有关更多信息,请参见Stu Halloway 编写的Clojure编程中的并发性一章。


2

列表的另一个区别是行为?

(list? (conj () 1)) ;=> true
(list? (cons 1 ())) ; => false

4
cons总是返回一个序列,conj返回与提供的序列相同的类型
孙宁

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.