Dec Code Story

Chapter #13 – Projects

ten declarative programming projects - instructive, useful, buildable

13.0  Prologue

Reading about declarative concepts builds vocabulary; building something with them builds intuition. Each project in this chapter is chosen to exercise a specific concept from the preceding chapters - persistent data structures, monadic composition, lazy streams, logic rules, FRP - while producing a program or library that is genuinely worth having. The goal is not toy exercises but small, complete artifacts you would actually reach for. The projects are language-independent specifications. The core algorithmic ideas are the same whether you choose Haskell, F#, Rust, or Python. Pick the language that best matches your current learning goals: Haskell maximizes exposure to the declarative model; Rust forces you to reconcile functional style with ownership; Python offers the fastest path from idea to working code.

13.1  Project Table

Project Specification Teaches Output
Parser Combinator Library Build map, and_then, or_else, many, and sequence combinators, then use them to parse JSON or a config format. Monadic composition, higher-order functions, error propagation with Result/Either. A reusable text parsing library with no dependencies.
Type-Safe SQL Query Builder Represent SELECT/WHERE/JOIN as algebraic data types; generate SQL strings at the leaves. Use phantom types to prevent invalid combinations such as a JOIN without ON. ADTs, phantom types, structural recursion over an expression tree. A library that builds SQL without string concatenation and catches structural errors at compile time.
Persistent Versioned Key-Value Store Implement a persistent hash array mapped trie (HAMT). Each insert and delete returns a new root; old roots remain valid. Track named versions explicitly. Structural sharing, persistent data structures, copy-on-write. An in-memory store with full history and O(log n) updates per operation.
Mini Rule Engine (Datalog subset) Facts are tuples; rules are Horn clauses. Implement semi-naive bottom-up evaluation to derive new facts until fixpoint. Logic programming, unification, fixpoint computation. An embeddable rule engine suitable for access control, dependency resolution, or business rules.
FRP Event Pipeline Model event streams as first-class values with map, filter, merge, scan, and switchMap. Connect to a real source: stdin, a file tail, or a timer. Functional reactive programming, dataflow, backpressure. A composable stream-processing library for real-time data.
Configuration DSL with Validation Design a small config language (key = value, sections, typed scalars). Parse it into an ADT, then validate with a schema expressed as rules returning accumulated Result/Either errors. ADTs, pattern matching, monadic error accumulation. A validated config parser with structured, multi-error reporting.
Spreadsheet Formula Evaluator Represent formulas as expression trees (literals, cell references, binary ops, built-in functions). Evaluate by structural recursion; detect circular references via topological sort. Term rewriting, recursive descent, lazy cell evaluation. An embeddable formula engine usable in any application with user-defined calculations.
Lazy Sequence Library Implement lazy cons cells or a pull-based iterator protocol from scratch. Build take, drop, zip, unfold, scan, and cycle on top. Lazy evaluation, corecursion, infinite data structures, thunks. A library for working with large or infinite sequences without materializing them.
STM-Based Concurrent Data Structures Using software transactional memory (or channels where STM is unavailable), implement a transactional queue, a bounded semaphore, a concurrent map, and a barrier - each as a composable unit. STM, composability of atomic operations, the limits of lock-based reasoning. A library of concurrent primitives that compose safely without deadlocks.
Constraint-Based Layout Engine Express UI layout as a set of linear constraints (width, height, spacing, alignment). Solve with the Cassowary algorithm or a simple linear solver. Drive a text-mode or SVG renderer from the solution. Constraint programming, declarative specification of geometry, separation of description from execution. A small layout engine that positions elements without procedural placement logic.

13.2  Epilogue

These ten projects span the full width of the Declarative Code Story: combinators and monads (parser, query builder, FRP pipeline), persistent data structures (versioned store, lazy sequences), logic and constraint systems (rule engine, layout engine), and effect management (STM library). No single project requires more than a few hundred lines of core code. Start with the one that overlaps most with work you are already doing - the parser combinator or the config DSL are natural first choices for most developers - then let the concepts guide you toward the others.