~ / track A / clojure basics

The seq abstraction

Intermediate

seq 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 first, rest, and cons. Code written against seq 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

seq projects any collection into its sequence view. Notice that a map seqs into a sequence of key-value pairs:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

first and rest work the same on all of them — that's the abstraction:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

Laziness

A lazy seq promises elements but doesn't realize them until needed. range with no argument is an infinite seq; take decides how much of it to actually produce:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

You can chain transformations over an infinite seq because nothing has to be computed eagerly:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

The pipeline reads as a recipe; only the final take 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.

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

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 map, filter, and take (no explicit recursion, no indices).

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate
 status: new