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
Set,Remove, orBatchdeltas - 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 ("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
The fixpoint implementation maintains exact reachability when roots and
edges are added or removed. See
IncrementalFixpointReport.md for the algorithm,
its invariants, and the limits of its evaluation data.
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