【发布时间】:2014-03-14 21:51:26
【问题描述】:
Clojure 语言中的 seq 和列表有什么区别?
(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])
这两种形式似乎被评估为相同的结果。
【问题讨论】:
Clojure 语言中的 seq 和列表有什么区别?
(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 始终是一个抽象。
seqs和lists的区别在于以下三个方面,如Clojure Programming
例如来自 Clojure 编程
(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"
此外,列表是它们自己的序列(实现细节):
(class (seq '(1 2 3))) => clojure.lang.PersistentList
人们总是可以使用cons 创建一个序列。查看this post 中的更多信息,了解cons 和conj 之间的区别。
【讨论】:
PersistentList 是一个具体的数据类型,而ISeq 是一个接口。 (PersistentList 实现了ISeq,这就是为什么所有“seq”函数都在列表上工作的原因)。 Clojure.org 关于序列的页面将 seq 描述为“允许 [ing] 许多数据结构以序列的形式提供对其元素的访问”。请参阅here 了解更多信息。
IPersistentList 是“列表”实现的通用类的接口,其中PersistentList 是显而易见的接口(但也包括PersistentQueue)。
Lists 是一个实现为链表的集合数据结构。 (其他核心集合数据结构是向量、映射和集合。)
Sequences 是一个列表抽象,可以应用于多种数据。将序列视为一种逻辑视图,可让您按顺序遍历 something 的元素。
列表是具体类型与抽象匹配的情况,因此列表实际上是一个序列。然而,有许多序列不是列表,而是一些其他实现,作为另一个数据结构的视图(如 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])])
产生...
([(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])
【讨论】: