Differences between a seq and a list
Asked Answered
T

3

10

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.

Teddytedeschi answered 14/3, 2014 at 21:51 Comment(1)
This should help: #19851230Counterstatement
T
22

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

1. getting the length of a seq can be costy:

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.

2. seqs can be lazy, whereas lists cannot.

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

3. seqs can be infinite, thus uncountable, whereas lists are always countable.

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.

Teddytedeschi answered 14/3, 2014 at 21:52 Comment(2)
Also, 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.Torus
IPersistentList is the interface for the general class of "list" implementations, of which PersistentList is the obvious one (but also includes PersistentQueue).Burget
B
12

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.

Burget answered 16/3, 2014 at 14:46 Comment(0)
C
2

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])
Cockup answered 15/3, 2014 at 16:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.