在Clojure语言中,seqs和lists有什么区别?
(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])
这两个表格似乎得出的结果是相同的。
首先,它们可能看起来一样,但实际上不是:
(class (list [1 2 3])) => clojure.lang.PersistentList
(class (seq [1 2 3])) => clojure.lang.PersistentVector$ChunkedSeq
list
通常是一种实现,而seq
始终是一种抽象。
如在Clojure Programming中指出,seq和list之间的区别在以下三个方面:
例如来自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
因为列表始终保持自身长度的记录,所以计算列表长度的操作成本是恒定的。然而,序列需要遍历自身才能检索其count
。
(class (range)) => clojure.lang.LazySeq
(class (apply list (range))) ;cannot be evaluated
; "java.lang.OutOfMemoryError: GC overhead limit exceeded"
此外,列表是它们自己的序列(实现细节):
(class (seq '(1 2 3))) => clojure.lang.PersistentList
使用cons
可以创建一个序列。有关cons
和conj
之间的差异,请查看此帖子获取更多信息。
PersistentList
是一个具体的数据类型,而 ISeq
是一个接口。(PersistentList
实现了 ISeq
,这就是为什么所有 "seq" 函数都可以在列表上工作的原因)。Clojure.org 上关于序列的页面将 seqs 描述为“允许许多数据结构将其元素作为序列提供访问”。更多信息请参见此处。 - jbmIPersistentList
是“列表”实现的通用类接口,其中 PersistentList
是显而易见的一个(但也包括 PersistentQueue
)。 - Alex Miller列表(Lists)是一种通过链表实现的集合数据结构(其他核心集合数据结构包括向量、映射和集合)。
序列(Sequences)是可应用于许多种数据的列表抽象。将序列视为一个逻辑视图,它可以让您按顺序遍历“某个东西”的元素。
列表是一个具体类型与抽象匹配的例子,因此列表实际上是序列。然而,有许多不是列表的序列,而是作为对另一个数据结构的视图的其他实现(例如clojure.lang.PersistentVector$ChunkedSeq)。
如果您仔细观察,核心库中的函数分为集合函数(以集合作为第一个参数并返回相同类型的集合)和序列函数(以“seqable”对象作为最后一个参数,将其转换为序列,执行其功能,并返回序列)。示例集合函数包括conj、assoc、count、get等。示例序列函数包括map、reduce、filter等。事实上,核心库的大部分工作都在序列上进行,而不是特定的集合类型。
序列是统一Clojure数据结构和所有FP函数的抽象。这种统一是Clojure代码简洁和可重用性的基础。
继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])])
produces ...
([(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])