Clojure Sequences
Sequences are a fundamental abstraction in Clojure that provide a uniform way to work with collections. Clojure's sequence library includes powerful tools for lazy evaluation and functional transformations.
Sequence Basics
All Clojure collections can be treated as sequences:
(seq [1 2 3]) ; => (1 2 3)
(seq #{1 2 3}) ; => (1 3 2) (order varies)
(seq {:a 1 :b 2}) ; => ([:a 1] [:b 2])
Lazy Sequences
Clojure can create infinite sequences that evaluate only when needed:
range
(take 5 (range)) ; => (0 1 2 3 4)
repeat
(take 3 (repeat "x")) ; => ("x" "x" "x")
cycle
(take 5 (cycle [1 2 3])) ; => (1 2 3 1 2)
iterate
(take 5 (iterate inc 0)) ; => (0 1 2 3 4)
Common Sequence Functions
map
(map inc [1 2 3]) ; => (2 3 4)
(map + [1 2 3] [4 5 6]) ; => (5 7 9)
filter
(filter even? (range 10)) ; => (0 2 4 6 8)
remove
(remove even? (range 10)) ; => (1 3 5 7 9)
take/drop
(take 3 (range 10)) ; => (0 1 2)
(drop 3 (range 10)) ; => (3 4 5 6 7 8 9)
take-while/drop-while
(take-while #(< % 5) (range 10)) ; => (0 1 2 3 4)
(drop-while #(< % 5) (range 10)) ; => (5 6 7 8 9)
Sequence Processing
concat
(concat [1 2] [3 4]) ; => (1 2 3 4)
interleave
(interleave [:a :b :c] [1 2 3]) ; => (:a 1 :b 2 :c 3)
interpose
(interpose "," ["a" "b" "c"]) ; => ("a" "," "b" "," "c")
partition
(partition 2 [1 2 3 4 5 6]) ; => ((1 2) (3 4) (5 6))
(partition 2 1 [1 2 3 4]) ; => ((1 2) (2 3) (3 4))
Reducing Sequences
reduce
(reduce + [1 2 3 4]) ; => 10
(reduce max [3 1 4 2]) ; => 4
reductions
(reductions + [1 2 3 4]) ; => (1 3 6 10)
into
(into [] (map inc [1 2 3])) ; => [2 3 4]
Transducers
Efficient, composable sequence transformations:
Creating Transducers
(def xf (map inc))
(def xf2 (filter even?))
Using Transducers
(into [] xf [1 2 3]) ; => [2 3 4]
(transduce xf + 0 [1 2 3]) ; => 9
Composing Transducers
(def xf (comp (map inc) (filter even?)))
(into [] xf [1 2 3 4]) ; => [2 4]
Lazy Sequence Patterns
Generating Infinite Sequences
(def fib-seq
(map first
(iterate (fn [[a b]] [b (+ a b)])
[0 1]))
(take 10 fib-seq) ; => (0 1 1 2 3 5 8 13 21 34)
Chunking
; Clojure evaluates sequences in chunks of 32 for efficiency
(take 1 (map #(do (println %) %) (range 100)))
; Prints 0-31 due to chunking
Performance Considerations
- Prefer
into
over repeatedconj
for building collections - Use transducers for efficient pipeline processing
- Be mindful of chunking behavior with side effects
- Consider
doseq
for side-effecting operations
Next Steps
Continue learning with:
- Clojure Macros - Extending the language with macros
- Concurrency - Working with state safely
- Java Interop - Using Java libraries from Clojure