The seq abstraction
Intermediateseqclojure.core/seqReturn a seq view of coll, or nil if empty.view on clojuredocs → is the way Clojure unifies everything that can be walked one item at a time under a single interface. Vectors, lists, maps, sets, strings, ranges, file lines, even custom types — all become logical lists with firstclojure.core/firstFirst item of a collection, or nil.view on clojuredocs →, restclojure.core/restItems after the first as a lazy seq.view on clojuredocs →, and consclojure.core/consLazy seq with x prepended to the rest.view on clojuredocs →. Code written against seqclojure.core/seqReturn a seq view of coll, or nil if empty.view on clojuredocs → works on any of them.
A second feature comes almost for free: most seqs are lazy. (range)
gives you an infinite sequence; nothing is produced until something asks.
Minimal example
seqclojure.core/seqReturn a seq view of coll, or nil if empty.view on clojuredocs → projects any collection into its sequence view. Notice that a map seqs into a sequence of key-value pairs:
firstclojure.core/firstFirst item of a collection, or nil.view on clojuredocs → and restclojure.core/restItems after the first as a lazy seq.view on clojuredocs → work the same on all of them — that's the abstraction:
Laziness
A lazy seq promises elements but doesn't realize them until needed. rangeclojure.core/rangeLazy seq of integers; (range), (range n), or (range start end step).view on clojuredocs → with no argument is an infinite seq; takeclojure.core/takeLazy seq of the first n items.view on clojuredocs → decides how much of it to actually produce:
You can chain transformations over an infinite seq because nothing has to be computed eagerly:
The pipeline reads as a recipe; only the final takeclojure.core/takeLazy seq of the first n items.view on clojuredocs → pulls five values, and each upstream step produces only enough output to satisfy that demand.
Practical example
Because seqs are uniform and lazy, the same pipeline works on data of any shape or size. Here it's a finite collection; switch to a stream of log lines or a database cursor, the code does not change.
Check yourself
? quiz
What does `(take 3 (range))` return, and why doesn't it loop forever?
Exercise
Write a single pipeline that yields the first five even squares, using only mapclojure.core/mapApply f to each element, returning a lazy seq.view on clojuredocs →, filterclojure.core/filterLazy seq of items where (pred x) is truthy.view on clojuredocs →, and takeclojure.core/takeLazy seq of the first n items.view on clojuredocs → (no explicit recursion, no indices).