What's the differences between seqs and lists in Clojure language?
(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])
These two forms seem to be evaluated as the same results.
What's the differences between seqs and lists in Clojure language?
(list [1 2 3]) => ([1 2 3])
(seq [1 2 3]) => ([1 2 3])
These two forms seem to be evaluated as the same results.
First of all, they may seem to be the same, but they're not:
(class (list [1 2 3])) => clojure.lang.PersistentList
(class (seq [1 2 3])) => clojure.lang.PersistentVector$ChunkedSeq
list
is usually an implementation, whereas seq
is always an abstraction.
The differences between seqs and lists lies in the following three aspects, as pointed out in Clojure Programming
e.g. from 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
Because a list always holds a record of its own length, so the operation of counting a list costs constant time. A seq, however, needs to traverse itself to retrieve its count
.
(class (range)) => clojure.lang.LazySeq
(class (apply list (range))) ;cannot be evaluated
; "java.lang.OutOfMemoryError: GC overhead limit exceeded"
Also, lists are their own seqs (implementation details):
(class (seq '(1 2 3))) => clojure.lang.PersistentList
One can always create a seq using cons
. Check out more information in this post for differences between cons
and conj
.
PersistentList
is a concrete datatype, whereas ISeq
is an interface. (PersistentList
implements ISeq
, which is why all the "seq" functions work on lists). The Clojure.org page on sequences describes seqs as "allow[ing] many data structures to provide access to their elements as sequences." See here for more.
IPersistentList
is the interface for the general class of "list" implementations, of which PersistentList
is the obvious one (but also includes PersistentQueue
).
Commented
Mar 16, 2014 at 20:53
Lists are a collection data structure implemented as a linked list. (Other core collection data structures are vectors, maps, and sets.)
Sequences are a list abstraction that can be applied to many kinds of data. Think of sequences as a logical view that lets you traverse the elements of something in order.
Lists are a case where the concrete type matches the abstraction, so lists actually are a sequence. However, there are many sequences that are not lists, but some other implementation as a view over another data structure (like clojure.lang.PersistentVector$ChunkedSeq).
If you look closely, functions in the core library are separated into either collection functions (which take a collection as the first argument and return a collection of the same type) and sequence functions (which take a "seqable" thing as the last argument, convert it to a sequence, perform their function, and return a sequence). Example collection functions are conj
, assoc
, count
, get
, etc. Example sequence functions are map
, reduce
, filter
, etc. In fact, the majority of the core library works on sequences, not particular collection types.
Sequences are the abstraction that unites all of the Clojure data structures with all of the FP functions in the core library. This unification is what underlies much of the conciseness and reusability of Clojure code.
Further to Albus Shin's answer ...
A list is one kind of sequence among several. You can't see any difference between them because Clojure prints them identically. Here are a few (with a vector thrown in for good measure):
=> (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])