liveBook · Manning

Sequenceable collection

As explained in Clojure: The Essential Reference

Seqable is the Clojure interface implemented by values that can provide a sequence view of their elements.

A sequenceable collection can provide a view of its elements for sequential access. In Clojure, collections implementing `clojure.lang.Seqable` support this behavior: call `seq` directly, or pass the collection to a function that uses `seq` internally. A collection need not be a list to be processed as a sequence. section 9.1 section 9.0

Access elements through a sequence

Given `(def numbers '(1 2 3 4))`, `(first numbers)` returns `1`, `(second numbers)` returns `2`, and `(last numbers)` returns `4`. Each function also accepts `nil` or an empty collection; it returns `nil` when the requested element is unavailable. section 3.5.1

The collection determines what its sequence view means:

  • A map yields key-value pairs. A hash map does not promise insertion order, so its “first” pair should not be treated as the first pair inserted. section 3.5.1
  • A set also has no inherent ordering. Use a sorted collection when its traversal order matters. section 3.5.1
  • `rseq` offers reverse access, while `subseq` and `rsubseq` select portions of sorted collections; these are alternatives to a forward `seq` view. section 9.1

Process more than one collection

`(map str (range 10) ["a" "b" "c"] "hijklm")` produces `("0ah" "1bi" "2cj")`. `map` accepts sequenceable inputs, returns a lazy sequence, and stops when its shortest input ends. section 3.5.2

For step-by-step traversal, `first` reads the head and `rest` or `next` advances. At the end, `rest` returns an empty list whereas `next` returns `nil`, making `next` useful as a loop condition. On a lazy input, choosing between them can also change how much work is forced. section 10.1 section 3.5.1

Table 3.7. Alternative ways to access the head or the tail for ordered collection types.

Type

Example

head

tail

PersistentList

'(1 2 3)

first, O(1)

last, O(n)

PersistentVector

[1 2 3]

nth/get, O(1)

peek, O(1)

PersistentQueue

(import 'clojure.lang.PersistentQueue) (PersistentQueue/EMPTY)

peek, O(1)

last, O(n)

PersistentTreeSet

(sorted-set 1 2 3)

first, O(1)

(first (rseq s)), O(log n)

PersistentTreeMap

(sorted-map :a 1 :b 2)

first, O(1)

(first (rseq s)), O(1)

PersistentArrayMap

(array-map :a 1 :b 2)

first, O(1)

last, O(n)

LongRange

(range 10)

first, O(1)

last, O(n)

LazySeq

(for [i [1 2]] i)

first, O(1)

last, O(n)

String

"abcd"

(.charAt "abcd" 0), O(1)

(.length "abcd"), O(1)

Compare head and tail operations by collection type. A shared sequence interface does not make every access equally efficient: for example, `last` is O(n) on a persistent list, while a vector has an O(1) `peek` operation. section 3.5.1

How Clojure: The Essential Reference covers it

How deep it goes
Defines the interface through `seq`, demonstrates access contracts and ordering caveats, and compares operation costs without explaining interface implementation.
Examples
Uses list access, unordered map and set traversal, multi-input `map`, and collection-specific head and tail costs.
What it assumes
Assumes familiarity with Clojure collection literals and function calls; introduces `seq` as the route to sequential access.
What you can do after
Apply it via `seq`, `first`, and `map` to process collections while checking ordering, missing elements, and lazy results.
How it connects
Connects `seq` with `first`, `rest`, `next`, `map`, reverse sequences, and sorted collections.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.