序列(seq)和列表(list)之间的区别

10

在Clojure语言中,seqs和lists有什么区别?

(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])

这两个表格似乎得出的结果是相同的。


1
这应该会有所帮助:https://dev59.com/9mIj5IYBdhLWcg3w04Mo#19850925 - guilespi
3个回答

22

首先,它们可能看起来一样,但实际上不是:

(class (list [1 2 3])) => clojure.lang.PersistentList
(class (seq [1 2 3])) => clojure.lang.PersistentVector$ChunkedSeq

list通常是一种实现,而seq始终是一种抽象。

如在Clojure Programming中指出,seq和list之间的区别在以下三个方面:

1. 获取seq的长度可能很昂贵:

例如来自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

2. 序列可以是惰性的,而列表则不能。

 (class (range)) => clojure.lang.LazySeq
 (class (apply list (range))) ;cannot be evaluated
 ; "java.lang.OutOfMemoryError: GC overhead limit exceeded"

3. 序列可以是无限的,因此不可数,而列表始终可数。

此外,列表是它们自己的序列(实现细节):

(class (seq '(1 2 3))) => clojure.lang.PersistentList

使用cons可以创建一个序列。有关consconj之间的差异,请查看此帖子获取更多信息。


1
此外,PersistentList 是一个具体的数据类型,而 ISeq 是一个接口。(PersistentList 实现了 ISeq,这就是为什么所有 "seq" 函数都可以在列表上工作的原因)。Clojure.org 上关于序列的页面将 seqs 描述为“允许许多数据结构将其元素作为序列提供访问”。更多信息请参见此处 - jbm
1
IPersistentList 是“列表”实现的通用类接口,其中 PersistentList 是显而易见的一个(但也包括 PersistentQueue)。 - Alex Miller

12

列表(Lists)是一种通过链表实现的集合数据结构(其他核心集合数据结构包括向量、映射和集合)。

序列(Sequences)是可应用于许多种数据的列表抽象。将序列视为一个逻辑视图,它可以让您按顺序遍历“某个东西”的元素。

列表是一个具体类型与抽象匹配的例子,因此列表实际上是序列。然而,有许多不是列表的序列,而是作为对另一个数据结构的视图的其他实现(例如clojure.lang.PersistentVector$ChunkedSeq)。

如果您仔细观察,核心库中的函数分为集合函数(以集合作为第一个参数并返回相同类型的集合)和序列函数(以“seqable”对象作为最后一个参数,将其转换为序列,执行其功能,并返回序列)。示例集合函数包括conj、assoc、count、get等。示例序列函数包括map、reduce、filter等。事实上,核心库的大部分工作都在序列上进行,而不是特定的集合类型。

序列是统一Clojure数据结构和所有FP函数的抽象。这种统一是Clojure代码简洁和可重用性的基础。


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])])

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])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接