Collections Clojure:cons(seq)vs.conj(list)
我知道Collections Clojure:cons(seq)vs.conj(list),collections,clojure,sequence,Collections,Clojure,Sequence,我知道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=> (c
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)
是否有使用列表的示例,其中
conj
与cons
表现出不同的行为,或者它们是真正可以互换的?用不同的措词,是否有一个例子,列表和seq不能等价地使用?我的理解是,你所说的是正确的:列表上的conj等同于列表上的cons
您可以将conj看作是一个“插入某处”操作,而cons则是一个“插入头部”操作。在列表中,最合乎逻辑的做法是在开头插入,因此在这种情况下conj和cons是等效的。一个区别是
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
,因此它上面的计数
不再是一个常数时间操作(在这种情况下,它可能会减少到1+3——1来自对第一个元素的线性遍历,3来自(下一个(Cons 4'(1 2 3))
是一个持久列表
,因此计数
)
我相信,这些名字背后的意图是,cons
意味着cons(构造顺序)1,而conj
意味着conj(将一个项目连接到一个集合上)由cons
构造的seq
以作为其第一个参数传递的元素开始,并将next
/rest
作为其seq
应用于第二个参数所产生的部分内容;如上所示,整个内容属于类clojure.lang.cons
,conj
始终返回与传递给它的集合类型大致相同的集合。(大致上,因为PersistentArrayMap
一旦超过9个条目就会变成PersistentHashMap
)
1传统上,在Lisp世界中,
cons
cons(构造一对),因此Clojure背离了Lisp的传统,让其cons
函数构造一个没有传统cdr
的seq“构造某种类型的记录以将多个值保存在一起”目前在编程语言及其实现的研究中无处不在;这就是“避免考虑另一个区别是,由于conj
将序列作为第一个参数,因此在将ref
更新为某个序列时,它与alter
配合得很好:
(dosync (alter a-sequence-ref conj an-item))
这基本上是以线程安全的方式执行
(conj a-sequence-ref an item)
。这不适用于cons
。有关更多信息,请参阅Stu Halloway中关于并发的章节。另一个区别是列表的行为
(list? (conj () 1)) ;=> true
(list? (cons 1 ())) ; => false
可以向任何顺序集合添加附加值或前置值:
(append [1 2] 3 ) ;=> [1 2 3 ]
(append [1 2] 3 4) ;=> [1 2 3 4]
(prepend 3 [2 1]) ;=> [ 3 2 1]
(prepend 4 3 [2 1]) ;=> [4 3 2 1]
多么精彩的一篇文章!我不知道有Cons类型。干得好!谢谢。听到这个消息很高兴。:-)顺便说一句,作为特例,
(Cons foo nil)
返回一个单例持久列表
(对于conj
),这是另一个极好的解释。你真是一个clojure绝地武士!根据我的经验,当性能很重要时,将列表视为列表而不是序列很重要。cons总是返回一个序列,conj返回的序列与提供的序列类型相同