The two starter-zones for RL are: "you know everything about the environment states and transitions", in which case we are dealing with dynamic programming, and "the environment is a Markov decision process (i.e. the dynamics are dependent only on your action and the current state, not the whole history)." There are arguably some techniques to know, e.g. a theorem that allows one to avoid differentiating through the environment, but that's really only interesting if we consider backpropagation to be the last word in what constitutes cybernetic feedback (spoiler, it isn't; we can do feedback at the prompt level between LLMs).

So what is there to take away from the foundations? My opinionated take is that there's really only one sort of pattern to take away, which is a common abstraction of the expectation, max, argmax, and Bellman operators. All of these are functionals or "higher-order" operators of type (X) → (XY) for some X and Y. I would like to abstract from these functionals a common computational pattern: in practice, computing these functionals starting with an input f: X, we use:

  1. A sampling map ς: X → !X to instantiate some iterated loop (represented by some bang operator !) over a representative sample of X
  2. An accumulator map ∫: Z × X × Z that folds over the "residuated" expression (idX ⊗ f) ∘ ΔX: XX, building up an intermediate result of type Z
  3. A postprocessing map ω: ZY that transforms the accumulated intermediate result into the final output

The intermediate type Z allows the accumulator to track auxiliary information (like running sums, best-so-far candidates, or normalisation constants) that gets refined into the final output by ω. For simple operators like 𝔼 and max, we have Z = Y and ω = id; for softmax, the accumulator builds up a normalising constant which ω uses to produce the final distribution. Schematically, such operators are depicted as shells that are applicable around other processes, like so:

General Operator Pattern

Let's see how some familiar operators fit into this mould. For each operator we specify the intermediate type Z, the accumulator ∫, and the postprocessor ω:

OperatorIntermediate ZAccumulator ∫Postprocess ω
𝔼z + wx · rid
maxmax(z, r)id
argmaxX × (x, r) if r > rbest else (xbest, rbest)π₁ (project)
softmaxz + exp(r)x ↦ exp(f(x))/z

Note: argmax accumulates both the best candidate and its score, then ω = π₁ projects out just the candidate. For softmax, the accumulator builds up the partition function Z=xexp(f(x))Z = \sum_{x'} \exp(f(x')), and then ω produces the normalised probability for each x by dividing exp(f(x))\exp(f(x)) by this accumulated normaliser.

Dynamic programming as composite functionals

The point of dynamic programming is to compute good policies. This decomposes into a composition of four functionals, each an instance of our accumulator pattern. Given a value function V: S:

  1. Inner expectation over next-states: 𝔼s'[V] : S × A

    • ςs,a: S → !S (sample from P(·|s,a))
    • ∫ = ∫𝔼, ω = id
  2. Q-function construction: QV(s,a) = R(s,a) + γ · 𝔼s'[V(s')]

    • This is just pointwise arithmetic, composing reward with discounted future value.
  3. Outer aggregation over actions — here we have three choices depending on what we want to compute:

    • 𝔼 with ω = id: policy evaluation (𝒯πV)(s)
    • max with ω = id: optimal value (𝒯*V)(s)
    • argmax with ω = π₁: greedy policy π'(s)
  4. Fixed-point iteration: iterate until convergence

    • ς: ℕ → !ℕ (unfold until ε < threshold)
    • Z = (S) × (current estimate and gap)
    • ∫: (V, ε), n, V' ↦ (V', ‖V' - V‖)
    • ω: (V, ε) ↦ V

The standard operators compose these as:

(TπV)(s)=Eaπouter[R(s,a)+γEsPinner[V(s)]](\mathcal{T}^\pi V)(s) = \underbrace{\int_{\mathbb{E}}^{a \sim \pi}}_{\text{outer}} \left[ R(s,a) + \gamma \cdot \underbrace{\int_{\mathbb{E}}^{s' \sim P}}_{\text{inner}} [V(s')] \right] (TV)(s)=maxaAouter[R(s,a)+γEsPinner[V(s)]](\mathcal{T}^* V)(s) = \underbrace{\int_{\textsf{max}}^{a \in A}}_{\text{outer}} \left[ R(s,a) + \gamma \cdot \underbrace{\int_{\mathbb{E}}^{s' \sim P}}_{\text{inner}} [V(s')] \right] greedy(V)(s)=argmaxaAouter[R(s,a)+γEsPinner[V(s)]]\textsf{greedy}(V)(s) = \underbrace{\int_{\textsf{argmax}}^{a \in A}}_{\text{outer}} \left[ R(s,a) + \gamma \cdot \underbrace{\int_{\mathbb{E}}^{s' \sim P}}_{\text{inner}} [V(s')] \right]

Value iteration computes V=fix(T)V^* = \text{fix}(\mathcal{T}^*), then extracts π=greedy(V)\pi^* = \text{greedy}(V^*).

Policy iteration alternates: fix(Tπ)greedyfix(Tπ)\text{fix}(\mathcal{T}^\pi) \to \text{greedy} \to \text{fix}(\mathcal{T}^{\pi'}) \to \cdots

Both are compositions of the same four building blocks — inner expectation, Q-construction, outer aggregation, and fixed-point iteration — just wired differently.

The Same Pattern with LLM Agents

The abstract decomposition pays off when we realise the same pattern applies beyond numerical computation. Consider an LLM-based agent deliberating in a text-based environment. The types change — State becomes natural language situation descriptions, Action becomes natural language action descriptions — but the structure is identical. Crucially, Value need not be a number: it can be a rich qualitative assessment mixing probabilistic hedging ("likely", "risky"), deontic judgement ("permissible", "obligatory"), social modelling ("they would expect...", "this signals..."), or aesthetic/intuitive grasp ("elegant", "feels off"). The accumulator's job is to synthesise such heterogeneous considerations into something actionable.

LLM policy improvement as composite functionals

Given a value-assessment function V: StateValue (an LLM prompted to assess situations):

  1. Inner expectation over consequences: 𝔼s'[V]: State × ActionValue

    • ςs,a: "What might happen if we do a in s? Consider likely outcomes, edge cases, how others might respond."
    • ∫: "Given these scenarios and their assessments, what's the overall prospect? Weigh by plausibility, but also note if any outcome is unacceptable regardless of likelihood."
    • ω = id
  2. Q-function construction: QV: State × ActionValue

    • Q: "The immediate situation from a is R(s,a); the downstream prospect is future. How do these combine? A small immediate cost might be worth it; an ethical violation might not be redeemable by future gains."
  3. Outer aggregation over actions — three modes:

    • ςsπ: "Which actions would I characteristically consider here?"
      • ∫: "Averaging over my tendencies, what's my overall assessment of the situation?"
      • ⇒ policy evaluation
    • ςs: "What are all the available moves, including unconventional ones?"
      • ∫: "Which option has the best overall assessment? (Best may involve tradeoffs: safest? most ethical? highest expected payoff?)"
      • ω = id: ⇒ optimal value
    • ςs, ∫ as above, but
      • ω = π₁: "Which action achieves that assessment?" ⇒ greedy policy
  4. Fixed-point iteration: fix: (StateValue) → (StateValue)

    • ς: "Have my assessments stabilised, or did that last round of reasoning change my view of some situations?"
    • ∫: "Update assessments in light of what I now know about downstream consequences."
    • ω: "Return the stable judgement."

The prompts are the "characteristic data" instantiating each functional. The same compositional structure — inner aggregation, Q-construction, outer aggregation, iteration — remains, but each box is now an LLM call that can fluidly mix probabilistic, logical, social, and intuitive reasoning as the situation demands.

Unified notation

Both the numerical and LLM-based formulations are instances of:

π(s)=ωfix(fix(Vωout(outςs[Q(R(s,),ωin(inςs,[V]))])))(s)\pi^*(s) = \omega_{\textsf{fix}}\Bigg( \textsf{fix}\bigg( V \mapsto \omega_{\textsf{out}}\Big( \int_{\textsf{out}}^{\varsigma_s} \big[ \mathsf{Q}\big(R(s,-),\, \omega_{\textsf{in}}\big(\int_{\textsf{in}}^{\varsigma_{s,-}}[V]\big)\big) \big] \Big) \bigg) \Bigg)(s)

where the characteristic data (ς, ∫, ω) for each functional determines whether we compute numerically or deliberate via prompted LLM calls, where "integration" can respect incommensurabilities that arithmetic would flatten.