Examples¶
Each of the eleven examples under examples/ is a plain script you run
directly with SBCL. Every one of them starts by loading the twelfth file,
examples/bootstrap.lisp, which pushes the repository root onto
asdf:*central-registry* and calls asdf:load-system "cl-dataflow" — so ASDF
resolves the load order and the cl-prolog dependency, and no script has to
restate the source-file list.
cl-prolog itself must already be somewhere ASDF can find it; nix develop
puts it on CL_SOURCE_REGISTRY for you (see
Getting Started).
sbcl --script examples/simple-pipeline.lisp
sbcl --script examples/event-workflow.lisp
sbcl --script examples/state-machine.lisp
sbcl --script examples/graph-analysis.lisp
sbcl --script examples/graph-toolkit.lisp
sbcl --script examples/state-machine-visualization.lisp
sbcl --script examples/resilient-pipeline.lisp
sbcl --script examples/streams.lisp
sbcl --script examples/graph-analysis-advanced.lisp
sbcl --script examples/stream-analytics.lisp
sbcl --script examples/integration.lisp
| Script | Demonstrates | Expected output |
|---|---|---|
simple-pipeline.lisp |
A four-stage make-pipeline — parse, validate, transform, render — built from explicit make-node handlers. |
Simple pipeline result: rendered: 70 |
event-workflow.lisp |
A pipeline stage emitting events and driving a state machine (see Getting Started). | The final workflow state and event trace. |
state-machine.lisp |
A standalone state-machine transition flow. | Final state: completed, the transition count, and the last transition record. |
graph-analysis.lisp |
Reachability analysis — descendants, ancestors, shortest path, boundaries — over a dataflow graph. | The downstream/upstream node sets, the shortest ingest -> load path, and the graph's source and sink nodes. |
graph-toolkit.lisp |
Strongly connected components, topological generations, transpose, distance, and DOT/Mermaid rendering. | Graph order/size, topological generations, a -> d distance, SCCs, and both diagrams. |
state-machine-visualization.lisp |
State/event enumeration, reachability, terminal and unreachable states, DOT/Mermaid rendering. | The state and event sets, reachable/unreachable/terminal states, the determinism verdict, and both diagrams. |
resilient-pipeline.lisp |
Retrying and fallback node wrappers (see Combinators and Resilience), plus result-threading pipeline sequencing. | Retry result: 70 (after 3 attempts), the fallback results, and the sequenced pipeline result. |
streams.lisp |
Lazy stream pipelines (map/filter/take/scan/flat-map/distinct) over an unbounded range (see Streams (Pull)). |
First 3 even squares: (4 16 36), running totals, the flat-mapped list, and the distinct sum. |
graph-analysis-advanced.lisp |
Critical path, topological rank, transitive reduction, weighted distance, density/bipartiteness, and a serialization round trip. | The critical path, topological rank, transitive-reduction edge count, weighted distance, density/bipartiteness, and a confirmed round trip. |
stream-analytics.lisp |
Frequencies, group-by, partition, sliding-window averages, and whole-stream mean. | Event frequencies, parity grouping, partition, sliding-window averages, and the mean of 1..100. |
integration.lisp |
An end-to-end scenario composing pipelines, graph analysis, pull streams, reactive subjects, a state machine, and context serialization. | The priced orders, high-value reactive alerts, the state-machine driving events, and a confirmed serialization round trip. |
Reading graph-analysis.lisp¶
This example models a small ingestion pipeline as a dependency graph and asks
two structural questions with graph-descendants/graph-ancestors:
(defparameter *graph* (cl-dataflow:make-graph))
(dolist (name '("ingest" "parse" "validate" "metrics" "transform" "audit" "load"))
(cl-dataflow:add-node *graph* (cl-dataflow:make-node name)))
(dolist (edge '(("ingest" "parse") ("parse" "validate") ("parse" "metrics")
("validate" "transform") ("validate" "audit") ("transform" "load")))
(cl-dataflow:add-edge *graph* (first edge) (second edge)))
;; Impact analysis: everything downstream of "parse".
(cl-dataflow:graph-descendants *graph* "parse")
;; Dependency analysis: everything "load" depends on.
(cl-dataflow:graph-ancestors *graph* "load")
graph-descendants/graph-ancestors answer "what breaks if I change this
node?" and "what does this node depend on?" directly, without hand-rolling a
traversal — both are linear over the bulk-query adjacency snapshot and
terminate on cyclic graphs. See Graph Algorithms for
the rest of the reachability and analysis surface.
Example scripts as regression tests¶
scripts/run-examples.sh (also wired as the examples flake check) runs
every example script as its own process under a hard timeout and asserts a
clean exit, which is what actually keeps this page honest.
t/core-runtime-example-test.lisp also defines one smoke test per example
script, asserting exact substrings of its output — but do not enable it
by setting CL_DATAFLOW_RUN_EXAMPLE_SMOKE=1: spawning the example processes
from inside the running test suite deadlocks it, confirmed by direct
reproduction. It stays opt-in, and unused, for exactly that reason. Use
scripts/run-examples.sh or run the scripts by hand instead — see
Development.