A library for incremental computation using reactive collections with delta-based updates.
This library provides composable reactive collections that automatically propagate changes through a computation graph. When source data changes, only the affected parts of derived collections are recomputed.
- Delta-based updates: Changes propagate as
Batchdeltas - Glitch-free semantics: Topological scheduling ensures consistent updates
- Composable combinators:
flatMap,join,union,fixpoint - Incremental fixpoint: Efficient transitive closure with support for additions and removals
open Reactive
(* Create a source collection *)
let (files, emit) = source ~name:"files" ()
(* Derive collections with combinators *)
let decls = flatMap ~name:"decls" files
~f:(fun _path data -> data.declarations)
()
let refs = flatMap ~name:"refs" files
~f:(fun _path data -> data.references)
~merge:PosSet.union
()
(* Join collections *)
let resolved = join ~name:"resolved" refs decls
~key_of:(fun pos _ref -> pos)
~f:(fun pos ref decl_opt -> ...)
()
(* Compute transitive closure *)
let reachable = fixpoint ~name:"reachable"
~init:roots
~edges:graph
()
(* Emit changes *)
emit (set_delta ("file.res", file_data))
emit (Batch [set "a.res" data_a; set "b.res" data_b])| Combinator | Description |
|---|---|
source |
Create a mutable source collection |
flatMap |
Transform and flatten entries, with optional merge |
join |
Look up keys from left collection in right collection |
union |
Combine two collections, with optional merge for conflicts |
fixpoint |
Compute transitive closure incrementally |
# Build the library
make build
# Run all tests
make test
# Clean build artifacts
make cleanTests are organized by theme:
| File | Description |
|---|---|
FlatMapTest.ml |
FlatMap combinator tests |
JoinTest.ml |
Join combinator tests |
UnionTest.ml |
Union combinator tests |
FixpointBasicTest.ml |
Basic fixpoint graph traversal |
FixpointIncrementalTest.ml |
Incremental fixpoint updates |
BatchTest.ml |
Batch processing tests |
IntegrationTest.ml |
End-to-end file processing |
GlitchFreeTest.ml |
Glitch-free scheduler tests |
The scheduler ensures that derived collections never see inconsistent intermediate states:
- Topological levels: Each node has a level based on its dependencies
- Accumulate phase: All deltas at a level are collected before processing
- Propagate phase: Nodes process accumulated deltas in level order
This prevents issues like:
- Anti-joins seeing partial data (e.g., refs without matching decls)
- Multi-level unions causing spurious additions/removals
This library powers the reactive dead code analysis in reanalyze:
ReactiveFileCollection: Manages CMT file processingReactiveMerge: Merges per-file data into global collectionsReactiveLiveness: Computes live declarations via fixpointReactiveSolver: Generates dead code issues reactively