Clojure语言中seqs和list之间的区别是什么?
(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])
这两种形式似乎被评估为相同的结果。
答案 0 :(得分:13)
首先,它们似乎是相同的,但它们不是:
(class (list [1 2 3])) => clojure.lang.PersistentList
(class (seq [1 2 3])) => clojure.lang.PersistentVector$ChunkedSeq
list
通常是一种实现,而seq
始终是一种抽象。
seqs和list之间的区别在于以下三个方面,如 Clojure Programming
中所述e.g。来自 Clojure Programming
(let [s (range 1e6)]
(time (count s))) => 1000000
; "Elapsed time: 147.661 msecs"
(let [s (apply list (range 1e6))]
(time (count s))) => 1000000
; "Elapsed time: 0.03 msecs
因为列表总是保存自己长度的记录,所以计算列表的操作需要花费不变的时间。但是,seq需要遍历自己以检索其count
。
(class (range)) => clojure.lang.LazySeq
(class (apply list (range))) ;cannot be evaluated
; "java.lang.OutOfMemoryError: GC overhead limit exceeded"
此外,列表是他们自己的seqs(实现细节):
(class (seq '(1 2 3))) => clojure.lang.PersistentList
总是可以使用cons
创建seq。请查看this post中有关cons
和conj
之间差异的更多信息。
答案 1 :(得分:7)
Lists是作为链表实现的集合数据结构。 (其他核心集合数据结构是向量,映射和集合。)
Sequences是一个列表抽象,可以应用于多种数据。将序列视为逻辑视图,可以按顺序遍历某些的元素。
列表是具体类型与抽象匹配的情况,因此列表实际上是一个序列。但是,有许多序列不是列表,而是一些其他实现作为另一个数据结构的视图(如clojure.lang.PersistentVector $ ChunkedSeq)。
如果仔细观察,核心库中的函数将分为集合函数(将集合作为第一个参数并返回相同类型的集合)和序列函数(它们采用" seqable&# 34;作为最后一个参数,将其转换为序列,执行其功能,并返回序列)。示例集合函数包括conj
,assoc
,count
,get
等。示例序列函数为map
,reduce
,{{1}事实上,大多数核心库都是基于序列而不是特定的集合类型。
序列是将所有Clojure数据结构与核心库中的所有FP函数结合在一起的抽象。这种统一是Clojure代码的简洁性和可重用性的基础。
答案 2 :(得分:2)
继Albus Shin的回答......
列表是几种中的一种序列。你不能看到它们之间的任何区别,因为Clojure以相同的方式打印它们。这里有一些(有很好的衡量标准):
=> (map (juxt identity seq? type)
[(range 1 4)
(take 3 (iterate inc 1))
(list 1 2 3)
(conj (list 2 3) 1)
(cons 1 (list 2 3))
[1 2 3]
(seq [1 2 3])])
产生......
([(1 2 3) true clojure.lang.LazySeq]
[(1 2 3) true clojure.lang.LazySeq]
[(1 2 3) true clojure.lang.PersistentList]
[(1 2 3) true clojure.lang.PersistentList]
[(1 2 3) true clojure.lang.Cons]
[[1 2 3] false clojure.lang.PersistentVector]
[(1 2 3) true clojure.lang.PersistentVector$ChunkedSeq])