Four schools of programming

Open any React codebase and you’re touching three programming paradigms at once: JSX is declarative, components are functional, useEffect is imperative. The fourth (actors, isolated entities passing messages) is what React doesn’t have. Multi-agent LLM frameworks are all scrambling to bolt it on. There are four schools of programming, and most of the interesting work happens at their seams.

SchoolUnitExemplarIrreducible becauseBreaks atPatched by
ImperativeStatementCThe world is mutable; you can't perceive your way out of pressing a buttonConcurrency safetyFunctional types (Rust borrow checker)
FunctionalExpressionHaskellA function has no inside; replace it with a lookup table and nothing changesSide effectsMonads, then algebraic effects
DeclarativeRelation, constraintProlog, SQLGoals describe what, not howPerformance and dynamismImperative escape hatches (PL/pgSQL, useEffect)
ActorsProcess, messageErlangIdentity, parallel cognition, no shared stateLarge-grain orchestrationDeclarative workflows (Temporal, BPMN)

Each paradigm’s complement patches exactly the seam it can’t reach alone.

Same program, four worldviews

The same toy program (Alice transfers 100 to Bob) becomes four different things, one per school. Each picture is a claim about what a program is.

Imperative: state mutates in time

“Do this, then this.” Named locations hold values; instructions overwrite them.

Imperative paradigm: Alice and Bob's balances shown at t=0 and t=1, with mutation arrows labeled -=100 and +=100 between them. Code shows alice.balance -= 100 and bob.balance += 100.

Functional: state is a value, function transforms it

No mutation. The old value still exists; a new value is computed from it.

Functional paradigm: an input value record {Alice: 500, Bob: 200} flows through a transfer function and produces a separate output value record {Alice: 400, Bob: 300}. Both values coexist; nothing was mutated.

Declarative: relations must hold

No order, no time. The solver finds bindings that satisfy every constraint.

Declarative paradigm: A.bal, Amt, B.bal as entity boxes connected to A_new and B_new by constraint nodes labeled greater-than-or-equal, minus, and plus. No flow direction; the relations simply must hold.

Actors: isolated state, messages cross

No shared memory. Each actor has a mailbox; the program is a conversation.

Actors paradigm: a caller sends a transfer message to Alice's mailbox; Alice processes it, decrements her local balance from 500 to 400, then sends a credit message to Bob's mailbox; Bob processes and increments his balance from 200 to 300. No shared memory between actors.

Imperative says a program is a sequence of state changes. Functional says it is a transformation between values. Declarative says it is a constraint network. Actors say it is a conversation between isolated entities.

The category-theoretic spine

Each paradigm has an algebraic structure underneath. Programming-language theory and category theory converge on the same definitions from different directions (natural breadcrumbs maps the translation in detail).

Paradigm / PairCategorical structureCategory Theory paper
ImperativeKleisli over an effect monadMoggi 1989
FunctionalMorphisms in a Cartesian closed categoryLambek & Scott 1986
DeclarativePredicates in a fibration over the baseKowalski 1974
ActorsCoalgebras for a behavior functorRutten 2000
Imp + FuncKleisli composition (monads, graded monads)Wadler 1992
Imp + DecHoare logic = predicate fibration over KleisliAtkey 2009
Imp + ActorsCoalgebras in Kleisli (effectful processes)Plotkin & Power 2001
Func + DecDependent types, fibrations over CCCsMartin-Löf 1984
Func + ActorsFinal coalgebras, FRP signalsElliott & Hudak 1997
Dec + ActorsBisimulation logic, behavior specs over coalgebrasMilner 1989

Six pairs

Four paradigms, choose two: six pairs. Each synthesis has its own history, canonical languages, and open frontier.

PairLanguagesFrontier
Imperative + Functional 1973 ML · 1990 Haskell (IO monad) · 1996 OCaml · 2004 Scala · 2005 F# · 2010 Rust (linear types) · 2011 Kotlin · 2012 Koka · 2014 Swift · 2022 OCaml 5 (effects) Algebraic effects replacing monad transformers; effect inference.
Imperative + Declarative 1969 Hoare logic · 1986 Eiffel (DbC) · 2008 Liquid Haskell · 2009 Dafny · 2011 F* · 2021 Lean 4 · 2024 LLM-aided proof (Goedel-Prover, …) Cost of writing a spec collapsing; verified projects newly economical.
Imperative + Actors 1986 Erlang · 2009 Akka · 2009 Go (CSP-lite) · 2010 Orleans (virtual actors) · 2015 Pony (no data races) · 2019 Temporal · 2023 Restate, Dapr Durable execution. Actors absorbing the database.
Functional + Declarative 1989 Coq · 1995 Mercury · 2007 Agda · 2007 Idris · 2021 Lean 4 (as a language) · 2021 egg / eqlog · Soufflé Datalog · differentiable Datalog (research) E-graphs for compilers; neuro-symbolic systems.
Functional + Actors 1986 Erlang · 2011 Elixir · 2017 Akka Typed · 2016 Unison Unison-style: content-addressed pure functions distributed across actors. Pure-vs-stateful becomes a deployment concern.
Declarative + Actors 1993 Honda session types · 2004 BPMN · ~2007 behavior trees (game AI) · 2019 Temporal workflows · 2023+ LangGraph / CrewAI / AutoGen / Inngest agents · multiparty choreographies Least settled. Where multi-agent LLM systems are about to live.

The least-explored pair is where multi-agent systems are about to live.

Lineage of paradigms and their syntheses

Programming-language pointers, oldest at top.

Long vertical timeline of programming languages from 1936 to 2014, with each entry tagged by a colored dot indicating its paradigm: imperative (blue), functional (green), declarative (red), actors (orange). Synthesis languages have two colored dots. Stars mark foundational works.

A language for cognitive architecture

Four schools, six bridges, one missing quad. Each pair has a decade of work behind it; the quad has a generation ahead of it.

The quad is the cognitive-architecture problem cosplaying as a programming language. The closest artifacts (React + Hooks, Erlang OTP, Algebraic effects, Behavior trees) each touch three of the four, but none unifies all. Soar and ACT-R hand-wired all four in the eighties; modern LLM stacks arrive the same way, gluing pure inference (functional) to tool calls (imperative) over a memory store (declarative) under a multi-agent runtime (actors). Each generation invents its own DSL (production rules, chunks, graph specs, role contracts), and the same primitives recur under different names. A canonical four-way language will crystallize the way Smalltalk did out of message-passing simulators, or Erlang out of Ericsson’s telecom: extracted from a generation of frameworks all reaching for the same abstractions.

If the pattern holds, we’re about 10 years out from a quad-paradigm language.