transducer
| Kind | kit |
|---|---|
| Categories | functional-programming data-processing |
| Keywords | transducer functional transformation composition |
Clojure-inspired transducers for composable, reusable transformations
Files
| File | Description |
|---|---|
.editorconfig | Editor formatting configuration |
.gitignore | Git ignore rules for build artifacts and dependencies |
.tool-versions | asdf tool versions (Zig, Kit) |
LICENSE | MIT license file |
README.md | This file |
docs/.keep | Placeholder for generated documentation |
examples/basic.kit | Basic transducer usage and convenience operations |
examples/data-pipeline.kit | Data pipeline example with filtering, mapping, batching, and aggregation |
examples/word-count.kit | Word count and vocabulary analysis example |
kit.toml | Package manifest with metadata, tasks, and dependencies |
src/transducer.kit | Main Kit.Transducer module |
tests/transducer.test.kit | Self-contained transducer tests |
Dependencies
No Kit package dependencies.
The package uses only the Kit standard library. Internally, distinct-into uses Persistent.PSet to track seen values.
Installation
kit add gitlab.com/kit-lang/packages/kit-transducer.gitUsage
import Kit.Transducer as T
double = fn(x) => x * 2
even? = fn(x) => Int.even? x
small? = fn(x) => x < 20
main = fn =>
# Compose transformations in left-to-right processing order
xf = T.compose [
T.map double,
T.filter even?,
T.filter small?
]
result = T.into xf [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
println "Transformed: ${result}"
# Convenience helper for compose + into
piped = T.pipe [
T.filter even?,
T.map (fn(x) => x * x)
] [1, 2, 3, 4, 5, 6]
println "Squared evens: ${piped}"
# Aggregation helpers
total = T.sum (T.filter even?) [1, 2, 3, 4, 5, 6]
println "Sum of evens: ${Int.to-string total}"
mainAPI Overview
Core Transducers
| Function | Description |
|---|---|
map | Applies a function to each element |
filter | Keeps elements where a predicate returns true |
remove | Drops elements where a predicate returns true |
cat | Flattens one level of nested lists |
mapcat | Maps each input to a list, then flattens |
keep | Keeps Some values returned by a function and drops None |
Composition and Application
| Function | Description |
|---|---|
compose | Combines transducers into one transformation |
transduce | Applies a transducer with a reducer, initial value, and input list |
into | Applies a transducer and collects the results into a list |
pipe | Convenience helper for compose plus into |
Collection Helpers
| Function | Description |
|---|---|
take-into, take-xf | Take the first n values, optionally after a transducer |
drop-into, drop-xf | Drop the first n values, optionally after a transducer |
take-while-into, take-while-xf | Take while a predicate remains true |
drop-while-into, drop-while-xf | Drop while a predicate remains true |
dedupe-into, dedupe-xf | Remove consecutive duplicate values |
distinct-into, distinct-xf | Keep only first occurrences |
interpose-into, interpose-xf | Insert a separator between values |
partition, partition-xf | Split a list into fixed-size chunks |
partition-by, partition-by-xf | Group consecutive values by key |
map-indexed, map-indexed-into | Transform values with their index |
Aggregation Helpers
| Function | Description |
|---|---|
count | Count values remaining after a transducer |
sum | Sum numeric values remaining after a transducer |
any? | Check whether any values remain |
none? | Check whether no values remain |
first | Return the first remaining value as Some value or None |
last | Return the last remaining value as Some value or None |
Design Notes
A transducer transforms one reducer into another reducer:
Transducer = (Reducer b a) -> (Reducer b c)
Reducer b a = (b, a) -> bThis lets transformation logic stay independent from collection logic. The same composed transformation can be used for collecting into a list, counting, summing, finding the first value, or other reductions.
Transducers are composed with left-to-right processing order:
xf = T.compose [T.map double, T.filter even?]The input is mapped first and filtered second.
When passing a Kit built-in as a first-class function in examples or applications, prefer a small local wrapper:
even? = fn(x) => Int.even? x
length = fn(s) => String.length sThis keeps interpreter and compiled output behavior aligned for higher-order usage.
Development
Running Examples
Run examples with the interpreter:
kit run examples/basic.kit
kit run examples/data-pipeline.kit
kit run examples/word-count.kitCompile an example to a native binary:
kit build examples/basic.kit && ./basicCompare interpreter and compiled output for all examples:
kit parity --no-spinner --failures-onlyRunning Tests
Run the test suite:
kit testRun the test suite with coverage:
kit test --coverageRunning kit dev
Run the standard development workflow (format, check, test):
kit devThis will:
- Format and check source files in
src/ - Run tests in
tests/with coverage
Generating Documentation
Generate API documentation from doc comments:
kit docNote: Kit sources with doc comments (##) will generate HTML documents in docs/*.html.
Cleaning Build Artifacts
Remove generated files, caches, parity results, and build artifacts:
kit task cleanNote: Defined in kit.toml.
Local Installation
To install this package locally for development:
kit installThis installs the package to ~/.kit/packages/@kit/transducer/, making it available for import as Kit.Transducer in other projects.
License
This package is released under the MIT License - see LICENSE for details.
Exported Functions & Types
map
(a -> b) -> Transducer a b
filter
(a -> Bool) -> Transducer a a
remove
(a -> Bool) -> Transducer a a
cat
Transducer (List a) a
mapcat
(a -> List b) -> Transducer a b
keep
(a -> Option b) -> Transducer a b
compose
List Transducer -> Transducer a b
transduce
Transducer a b -> (c -> b -> c) -> c -> List a -> c
into
Transducer a b -> List a -> List b
take-into
Int -> List a -> List a
take-xf
Int -> Transducer a b -> List a -> List b
drop-into
Int -> List a -> List a
drop-xf
Int -> Transducer a b -> List a -> List b
take-while-into
(a -> Bool) -> List a -> List a
take-while-xf
(b -> Bool) -> Transducer a b -> List a -> List b
drop-while-into
(a -> Bool) -> List a -> List a
drop-while-xf
(b -> Bool) -> Transducer a b -> List a -> List b
dedupe-into
List a -> List a
dedupe-xf
Transducer a b -> List a -> List b
distinct-into
List a -> List a
distinct-xf
Transducer a b -> List a -> List b
interpose-into
a -> List a -> List a
interpose-xf
b -> Transducer a b -> List a -> List b
map-indexed
(Int -> a -> b) -> Transducer a b
map-indexed-into
(Int -> a -> b) -> List a -> List b
count
Transducer a b -> List a -> Int
sum
Transducer a Int -> List a -> Int
any?
Transducer a b -> List a -> Bool
none?
Transducer a b -> List a -> Bool
first
Transducer a b -> List a -> Option b
last
Transducer a b -> List a -> Option b
partition
Int -> List a -> List (List a)
partition-xf
Int -> Transducer a b -> List a -> List (List b)
partition-by
(a -> b) -> List a -> List (List a)
partition-by-xf
(b -> c) -> Transducer a b -> List a -> List (List b)
pipe
List Transducer -> List a -> List b