(sigil seq)
(sigil seq) - Polymorphic Sequences and Transducers
Unified collection processing that works across lists, vectors, and dicts. Built on transducers for composable, efficient transformations.
Polymorphic Operations
When imported, these shadow the single-type versions from prelude:
(import (sigil seq))
(map square '(1 2 3)) ; => (1 4 9)
(map square #(1 2 3)) ; => #(1 4 9)
(filter even? '(1 2 3 4)) ; => (2 4)
(filter even? #(1 2 3 4)) ; => #(2 4)Transducers
Transducers are composable transformation pipelines:
(define xform
(comp (filtering even?)
(mapping square)
(taking 5)))
(transduce xform conj '() (iota 100)) ; => (0 4 16 36 64)Transducers separate the "what" (transformation) from the "how" (iteration), enabling the same transformation to work on any collection type.
Stream Processing with Channels
The same transducers work for processing channel message streams:
(import (sigil seq)
(sigil channels)
(sigil async))
(define log-xform
(comp (filtering (lambda (msg) (equal? (dict-ref msg level:) "error")))
(mapping (lambda (msg) (dict-ref msg text:)))))
(with-async
;; Producer: send log messages
(go (for-each (lambda (msg) (channel-send logs msg))
messages)
(channel-close! logs))
;; Consumer: process with transducer
(go (for-channel (msg logs)
(let ((xrf (log-xform (lambda (acc x) (println "ERROR: ~a" x) acc))))
(xrf #f msg)))))Exports
mappingprocedureCreate a mapping transducer.
Transforms each element by applying f.
(transduce (mapping square) conj '() '(1 2 3)) ; => (1 4 9)filteringprocedureCreate a filtering transducer.
Keeps only elements satisfying the predicate.
(transduce (filtering even?) conj '() '(1 2 3 4)) ; => (2 4)takingprocedureCreate a taking transducer.
Takes at most n elements, then terminates early.
(transduce (taking 3) conj '() '(1 2 3 4 5)) ; => (1 2 3)droppingprocedureCreate a dropping transducer.
Skips the first n elements.
(transduce (dropping 2) conj '() '(1 2 3 4 5)) ; => (3 4 5)taking-whileprocedureCreate a taking-while transducer.
Takes elements while predicate is true, then stops.
(transduce (taking-while (lambda (x) (< x 4))) conj '() '(1 2 3 4 5))
; => (1 2 3)dropping-whileprocedureCreate a dropping-while transducer.
Drops elements while predicate is true, then takes the rest.
(transduce (dropping-while (lambda (x) (< x 3))) conj '() '(1 2 3 4 5))
; => (3 4 5)catprocedureConcatenating transducer.
Flattens one level of nesting.
(transduce cat conj '() '((1 2) (3 4))) ; => (1 2 3 4)mapcatprocedureMapcat transducer (map then concatenate).
Like (comp (mapping f) cat) but slightly more efficient.
(transduce (mapcat (lambda (x) (list x x))) conj '() '(1 2 3))
; => (1 1 2 2 3 3)compprocedureCompose transducers left-to-right.
Unlike function composition, transducers compose in reading order.
(comp (filtering even?) (mapping square) (taking 3))conjprocedureReducer for building lists.
(transduce (mapping square) conj '() '(1 2 3)) ; => (1 4 9)conj-vecprocedureReducer for building vectors.
Note: builds a list then converts (vectors are immutable).
conj-dictprocedureReducer for building dicts from (key . value) pairs.
transduceprocedureApply a transducer to a collection.
The core transducer execution function.
(transduce (mapping square) conj '() '(1 2 3)) ; => (9 4 1)
(transduce (mapping square) + 0 '(1 2 3)) ; => 14intoprocedureTransform and collect into a collection of the same type.
(into '() (mapping square) '(1 2 3)) ; => (9 4 1)
(into #() (mapping square) '(1 2 3)) ; => #(1 4 9)sequenceprocedureTransform a collection, preserving its type.
(sequence (mapping square) '(1 2 3)) ; => (1 4 9)
(sequence (mapping square) #(1 2 3)) ; => #(1 4 9)mapprocedureApply a procedure to each element, returning a collection of the same type.
Works on lists, vectors, arrays, and dicts.
(map square '(1 2 3)) ; => (1 4 9)
(map square #(1 2 3)) ; => #(1 4 9)
(map cdr #{ a: 1 b: 2 }) ; => (1 2) - maps over entriesfilterprocedureReturn elements satisfying a predicate, preserving collection type.
(filter even? '(1 2 3 4)) ; => (2 4)
(filter even? #(1 2 3 4)) ; => #(2 4)foldprocedureReduce a collection with a procedure.
Works on lists, vectors, arrays, and dicts.
(fold + 0 '(1 2 3 4)) ; => 10
(fold + 0 #(1 2 3 4)) ; => 10for-eachprocedureApply a procedure to each element for side effects.
(for-each println '(1 2 3))
(for-each println #(1 2 3))anyprocedureTest if any element satisfies a predicate.
(any even? '(1 3 4 5)) ; => #t
(any even? #(1 3 5 7)) ; => #feveryprocedureTest if all elements satisfy a predicate.
(every even? '(2 4 6)) ; => #t
(every even? #(2 3 4)) ; => #ffindprocedureFind the first element satisfying a predicate.
Returns #f if no element matches.
(find even? '(1 3 4 5)) ; => 4
(find even? '(1 3 5 7)) ; => #f