---
title: Calculus of Monolithic Copatterns
url: https://www.emergentmind.com/topics/calculus-of-monolithic-copatterns
type: topic
---

# Calculus of Monolithic Copatterns

Searching arXiv for the cited paper and closely related work to ground the article.
{"query":"arXiv:2508.12427 Controlling Copatterns: There and Back Again (Extended Version)", "max_results": 5}
{"query":"copatterns Danvy functional syntactic correspondence refocusing abstract machine CPS arXiv", "max_results": 10}
Calculus of monolithic copatterns is a core formulation of copattern matching in which programs are treated not merely as functions over arguments, but as responses to a calling context whose shape determines clause selection. In "Controlling Copatterns: There and Back Again (Extended Version)" the monolithic copattern calculus is presented as a deliberately small core language that captures the essential behavior of copattern matching used in the paper’s Scheme/Racket examples, while omitting the extra compositional features introduced later. Its semantic development proceeds through a small-step operational semantics, an abstract machine, and a continuation-passing style (CPS) interpretation, derived by standard semantic correspondences [2508.12427].

## 1. Core language and contextual interpretation

The monolithic copattern calculus is introduced as a language with ordinary variables, ordinary application, a projection or index form, a dot form for explicit self-application, and objects written as a list of copattern clauses [2508.12427]. Its syntax is given by
\[
\mathit{Variable} \ni x, y, z ::= \dots
\]
\[
\mathit{Index} \ni X, Y, Z ::= \dots
\]
\[
\mathit{Term} \ni M, N ::= x \mid M~N \mid M~X \mid M. \mid \lambda\{\many{O}\}
\]
\[
\mathit{Option} \ni O ::= L \to M
\]
\[
\mathit{Copat} \ni L ::= \varepsilon \mid x~L \mid X~L
\]

A term \(M\) is therefore either a variable, an application \(M~N\), an indexed projection/application \(M~X\), a self-reference \(M.\), or an object \(\lambda\{\dots\}\). An option \(L \to M\) specifies that if the surrounding context matches copattern \(L\), the object returns \(M\). A copattern \(L\) is a sequence of demands on the context: \(x~L\) requires an argument term in the context, \(X~L\) requires a particular index or projection tag, and \(\varepsilon\) requires no further context.

The defining intuition is that a copattern is a context pattern. This is the dual of ordinary pattern matching: instead of matching the shape of a value, the program matches the shape of the call context. A common misconception is to assimilate copattern clauses to ordinary elimination forms over already constructed data. In the monolithic calculus, however, the operative object is the surrounding evaluation context itself. Clause selection is controlled by how the object is observed.

The calculus is described as monolithic because this matching is all-or-nothing and packaged into a single, multi-clause object definition. This suggests a semantics in which a single object performs one large matching problem against the current question posed by its context, rather than composing smaller matching components.

## 2. Primitive equations, first-match behavior, and self-reference

The equational specification of the calculus is organized around two primitive equations [2508.12427]:
\[
(\delta)\quad M. = M~M
\]
and
\[
(\beta)\quad C[\lambda\{\many[1 \leq i \leq n]{L_i \to M_i}\}] = M_j\vect{\subst{x}{N}}
\]
under the conditions that \(C = L_j\vect{\subst{x}{N}}\), and for all \(i < j\), there is no matching decomposition \(C = L_i\vect{\subst{x}{N}}\).

The \((\delta)\) equation makes self-reference explicit. The dot form means “pass me myself as the first argument,” so \(M.\) expands to \(M~M\). The paper characterizes this as the mechanism by which open recursion is represented in the calculus. Self is therefore not implicit in the metalanguage; it is an explicit operational construct of the object language.

The \((\beta)\) equation is the core copattern-matching rule. A lambda-object examines the surrounding context \(C\), tries its clauses in order, and selects the first matching one. The semantics is therefore first-match: the first clause whose copattern matches the context is the clause that fires. If \(L_j\) matches the context, then the corresponding right-hand side \(M_j\) is returned with the variables bound by the match substituted in.

The paper’s stream-like counter example exhibits this control structure:
\[
\mathit{count} = \lambda \begin{aligned}[t] \{& \mathit{self}~\mathit{From}~x~\mathit{Head} \to x \\
\mid& \mathit{self}~\mathit{From}~x~\mathit{Tail} \to \mathit{self}.\mathit{From}(\mathit{succ}~x) \} \end{aligned}
\]
Here the object’s behavior is determined by the observation made of it: asking for `Head` returns the current number, while asking for `Tail` returns the next stream object by recursive self-application. This makes explicit that behavior is context-sensitive in a precise operational sense.

## 3. Small-step operational semantics

The small-step operational semantics is derived in an algorithmic form, first implemented in Haskell and then re-expressed as a relational stepping system [2508.12427]. The concrete syntax is represented by the following data structures:
```haskell
data Term i a = Var a | Term i a :*: Term i a | Term i a :@: i | Dot (Term i a) | Obj [Option i a]
data Option i a = Copattern i a :-> Term i a
data Copattern i a = Nop | a :* Copattern i a | i :@ Copattern i a
```
The paper then defines
```haskell
type Question i a = Copattern i (Term i a)

ask :: Term i a -> Question i a -> Term i a
ask m Nop      = m
ask m (n :* q) = ask (m :*: n) q
ask m (i :@ q) = ask (m :@: i) q
```
so that a `Question` is literally an evaluation context in the same shape as a copattern.

Reduction is split between a redex-reduction phase and a search or refocus phase. The redex structures are
```haskell
data Redex i a = Introspect (Term i a) | Respond [Option i a] | FreeVar a
data Reduct i a = Reduced (Term i a) | Unhandled | Unknown a
data Followup i a = Next (Reduct i a) (Question i a) | More (Copattern i a) (Term i a) [Option i a] (Question i a)
```
where `Introspect m` corresponds to \(M.\), `FreeVar x` records an unbound variable, and `Respond ops` dispatches object clauses.

The central matching procedure is `comatch`, which compares a clause’s left-hand copattern with the current question:
```haskell
data CoMatch i a b = Comatch { prefix :: Env a b, suffix :: Remainder i a b }
data Remainder i a b = Followup (Copattern i b) | Unasked  (Copattern i a) | Mismatch (Copattern i a) (Copattern i b)
```
with
```haskell
comatch Nop        cxt  = Comatch [] (Followup cxt)
comatch lhs        Nop  = Comatch [] (Unasked lhs)
comatch (x :* lhs) (y :* cxt)   = Comatch ((x, y) : prefix q) (suffix q)
  where q = comatch lhs cxt
comatch (i :@ lhs) (j :@ cxt)
  | i == j = comatch lhs cxt
comatch lhs cxt = Comatch [] (Mismatch lhs cxt)
```
An empty copattern succeeds immediately, leaving the remaining context as followup; a nonempty copattern against empty context is `Unasked`; matching argument prefixes binds variables; matching index prefixes checks equality of tags; otherwise the result is `Mismatch`.

Search for the next redex builds the surrounding question:
```haskell
data Found i a = Asked (Redex i a) (Question i a)

search :: Term i a -> Found i a
search (Var x)   = Asked (FreeVar x) Nop
search (Dot m)   = Asked (Introspect m) Nop
search (Obj ops) = Asked (Respond ops) Nop
search (m :*: n) = case search m of
  Asked r q -> Asked r $ q <> n :* Nop
search (m :@: i) = case search m of
  Asked r q -> Asked r $ q <> i :@ Nop
```
The paper explicitly notes that this is the call-by-name evaluation order: evaluation contexts correspond exactly to questions.

The refocusing formulation is
```haskell
data Decomp i a = Asked (Redex i a) (Question i a)
decomp m = refocus m Nop
```
with
```haskell
refocus (Var x)   k = Asked (FreeVar x) k
refocus (Dot m)    k = Asked (Introspect m) k
refocus (Obj eqs)  k = Asked (Respond eqs) k
refocus (m :*: n)  k = refocus m $ n :* k
refocus (m :@: i)  k = refocus m $ i :@ k
```
and the key lemma
\[
\texttt{decomp (recomp m k) = refocus m k}.
\]

The direct-style evaluator iterates decomposition, reduction, and recomposition:
```haskell
eval m = iter $ decomp m
iter (Asked r q) = case reduce r q of
  Next (Reduced m) k -> eval $ recomp m k
  Next (Unknown x) k -> Stuck x k
  Next Unhandled   k -> Raise k
  More lhs rhs eqs k -> Under lhs rhs eqs k
```
This yields the corresponding reduction semantics with inside-out evaluation contexts
\[
\mathit{Cont} \ni K ::= \varepsilon \mid N~K \mid X~K
\]
and rules
\[
(\delta)\quad K[M.] \mapsto K[M~M]
\]
\[
(\beta)\quad K[\lambda\{\many[1 \leq i \leq n]{L_i \to M_i}\}] \mapsto K'[M_j\many{\subst{x}{N}]} 
\]
if \(\mathit{comatch}(L_j, K) = (\vect{\subst{x}{N}, K'})\) and earlier clauses do not match. The operational semantics is thus a call-by-name reduction semantics specialized to copattern-matching objects, with the context as an active participant in matching.

## 4. Abstract machine and explicit control flow

The abstract machine is derived through the standard functional and syntactic correspondence pipeline: CPS-transform the evaluator, defunctionalize continuations, fuse loops, and simplify [2508.12427]. The resulting machine is tail-recursive and structurally aligned with the small-step semantics. Its core interpreter is
```haskell
eval m = refocus m Nop

refocus (Var x)   k = Stuck x k
refocus (Dot m)   k = refocus m $ m :* k
refocus (Obj os)  k = case os of
  []               -> Raise k
  lhs :-> rhs : os -> comatch lhs k rhs os k
refocus (m :*: n)  k = refocus m $ n :* k
refocus (m :@: i)  k = refocus m $ i :@ k
```
and the object-matching continuation is
```haskell
comatch Nop         cxt       rhs _  _ = refocus rhs cxt
comatch lhs         Nop       rhs os q = Under lhs rhs os q
comatch (x :* lhs) (y :* cxt) rhs os q
  = comatch lhs cxt (rhs // [(x,y)]) os q
comatch (i :@ lhs) (j :@ cxt)
  | i == j = comatch lhs cxt rhs os q
comatch lhs         cxt       _   os q   = refocus (Obj os) q
```
The paper explicitly notes that this machine is not yet environment-based because it performs substitution directly by `rhs // ...`, and that an environment-based version appears later in the appendix.

The machine states are summarized as two forms: a refocusing or reduction state \(\cut{M}{K}\), and a copattern-matching state \(\braket{L \cmid K \cmid M \cmid \many{O} \cmid K}\). The initial state is
\[
\cut{M}{\varepsilon}
\]
and the final states are:
\[
\cut{x}{K},
\]
for an unknown variable,
\[
\cut{\lambda\{\}}{K},
\]
for an unhandled question, and
\[
\braket{L \cmid \varepsilon \cmid M \cmid \many{O} \cmid K}
\]
with \(L \neq \varepsilon\), for an underspecified question.

Its transition system makes the control structure of monolithic copattern matching explicit:
\[
\cut{M~N}{K} \mapsto \cut{M}{N~K}
\qquad
\cut{M~X}{K} \mapsto \cut{M}{X~K}
\]
\[
\cut{M.}{K} \mapsto \cut{M}{M~K}
\]
\[
\cut{\lambda\{L \to M \mid \many{O}\}}{K} \mapsto \braket{L \cmid K \cmid M \cmid \many{O} \cmid K}
\]
\[
\braket{x ~ L \cmid N ~ K' \cmid M \cmid \many{O} \cmid K} \mapsto \braket{L \cmid K' \cmid M\subst{x}{N} \cmid \many{O} \cmid K}
\]
\[
\braket{X ~ L \cmid X ~ K' \cmid M \cmid \many{O} \cmid K} \mapsto \braket{L \cmid K' \cmid M \cmid \many{O} \cmid K}
\]
\[
\braket{\varepsilon \cmid K' \cmid M \cmid \many{O} \cmid K} \mapsto \cut{M}{K'}
\]
\[
\braket{L \cmid \varepsilon \cmid M \cmid \many{O} \cmid K} \not\mapsto \qquad (\text{if } L \neq \varepsilon)
\]
\[
\braket{L \cmid K' \cmid M \cmid \many{O} \cmid K} \mapsto \cut{\lambda\{\many{O}\}}{K} \qquad (\text{otherwise})
\]

This machine exposes a key structural fact about the calculus: monolithic copattern matching is a controlled traversal of the demanded context. The machine either binds argument positions, checks index demands, succeeds by exhausting the copattern, blocks because the question is too short, or falls through to the next clause because the present clause cannot answer.

## 5. CPS interpretation and semantic correspondence

The CPS translation is extracted from the abstract machine by desugaring nested patterns, \(\eta\)-reducing, and applying transitions eagerly [2508.12427]. The Haskell-like semantic domains are:
```haskell
type CPSQuestion i a = Copattern i (CPSArg i a)
type CPSTerm i a = CPSQuestion i a -> Answer i a
type CPSOption i a = CPSTerm i a -> CPSTerm i a
type CPSCopat i a = CPSQuestion i a -> CPSOption i a

newtype CPSArg i a = Arg { useArg :: CPSTerm i a }
data CPSVar i a = Name a | Subs (CPSTerm i a)
```
The role of `CPSVar` is that a variable may be either a source-level name, `Name`, or a semantic substitution, `Subs`, when translating under binders.

The term translation is
```haskell
term (Var (Name x)) = Stuck x
term (Var (Subs m)) = m
term (Dot m)   = \k -> (term m) (Arg(term m) :* k)
term (Obj os)  = options os
term (m :*: n) = \k -> (term m) (Arg(term n) :* k)
term (m :@: i) = \k -> (term m) (i :@ k)
```
and option lists are translated by
```haskell
options [] = Raise
options (lhs :-> rhs : os)   = \q -> (comatch lhs rhs) q (options os) q
```
while clause translation is given by
```haskell
comatch Nop        rhs = \_ _   -> (term rhs)
comatch (x :* lhs) rhs = \q os -> \case
  (y :* k) -> (comatch lhs (rhs // [(x, n)])) q os k
  Nop      -> Under $ (comatch (x :* lhs) rhs) q os
  _        -> os q
  where n = Var (Subs (useArg y))
comatch (i :@ lhs) rhs = \q os -> \case
  (j :@ k)     | i == j -> (comatch lhs rhs) q os k
  Nop      -> Under $ (comatch (i :@ lhs) rhs) q os
  _        -> os q
```

The mathematical CPS equations summarize the same translation:
\[
\den{x} = x \qquad
\den{M.} = \lambda k.\, \den{M}~(\den{M},k) \qquad
\den{M~N} = \lambda k.\, \den{M}~(\den{N},k) \qquad
\den{M~X} = \lambda k.\, \den{M}~(X~k)
\]
\[
\den{\lambda\{\many{O}\}} = \den{\many{O}}
\]
For option lists:
\[
\den{\varepsilon} = \lambda k.\, k
\]
\[
\den{L \to M \mid \many{O}} = \lambda k.\, \den{L \to M}~k~\den{\many{O}~k}
\]
and for a clause:
\[
\den{\varepsilon \to N} = \lambda q.\lambda f.\, \den{N}
\]
\[
\den{x ~ L \to N} =
\Rec r = \lambda q.\lambda f.\lambda k.\,
\Case k \Of
\begin{aligned}[t]
&(x, k') \to \den{L \to N}~q~f~k' \\
&() \to r~q~f \\
&k \to f~q
\end{aligned}
\]
with an analogous equation for \(X ~ L \to N\).

The defining idea is that the continuation is not merely the rest of computation; it is a representation of the question being asked of the object. This is the CPS counterpart of the operational identification of evaluation contexts with questions.

The semantic correspondence theorem states that the three evaluators are extensionally equal. The paper isolates the observation of “raising an unanswered question” through the equivalence of the following conditions:
\[
M \mapsto^* K[\lambda\{\many{L_i \to M_i}\}]
\]
such that
\[
\forall i,\ \mathit{comatch}(L_i,K) = \mathit{Mismatch},
\]
\[
\cut{M}{\varepsilon} \mapsto^* \cut{\lambda\{\}}{K},
\]
and
\[
\den{M}() \mapsto^* \den{K}
\]
where
\[
\den{\varepsilon} = () \qquad
\den{N~K} = (\den{N}, \den{K}) \qquad
\den{X~K} = X~\den{K}.
\]
Accordingly, the direct small-step semantics, the abstract machine, and the CPS translation determine the same observable behavior.

## 6. Relation to compositional copatterns and broader significance

The paper develops the monolithic calculus first and then refactors it into a more expressive compositional calculus within CPS [2508.12427]. This later system is not simply additional surface syntax. It changes the control structure by introducing explicit delimitation of context, explicit handling of match failure, and nested matching forms.

Three refactorings are singled out. First, delimiting the context introduces a delimiter \(M!\) and first-class delimited questions:
\[
\mathit{Response} \ni R ::= q \mid \varepsilon \mid M \ans R
\]
\[
\mathit{Term} \ni M,N ::= \dots \mid \ans q \to R
\]
with CPS clauses
\[
\den{M \ans R} = \den{M}~\den{R} \qquad
\den{\varepsilon} = () \qquad
\den{q} = q \qquad
\den{\ans q \to R} = \lambda q.\, \den{R}.
\]
Second, copatterns are nested into smaller units:
\[
\mathit{Term} ::= \dots \mid O \ask M
\]
\[
\mathit{Option} ::= x \to O \mid X \to O \mid \ask x \to M
\]
where \(O \ask M\) means “try option \(O\), and if it fails continue with \(M\),” and \(\ask x \to M\) marks the success/failure split. Third, the CPS treatment is refined through `Opt` and `Opt'` to avoid duplication of continuations:
\[
Opt\den{O} ~ (q \compq k) ~ f ~ k = Opt'\den{O} ~ (\lambda k'.~ f ~ (q \compq k')) ~ k
\]
and
\[
Opt\den{O} ~ k ~ f ~ k = Opt'\den{O} ~ f ~ k.
\]

Against this background, the role of the monolithic calculus becomes clearer. It is the minimal setting in which copattern matching can be studied as a semantics of context-sensitive behavior. In the monolithic system, a context is implicit in the surrounding evaluation context, failure is implicit in clause ordering, and a clause’s left-hand side is a single large copattern. In the compositional system, questions become first-class and delimited, failure becomes explicit and composable, copatterns become nested, CPS gains an extra response layer, and the machine tracks a meta-continuation.

The paper presents this progression as a semantic pipeline: source-level reduction yields an executable abstract machine, which in turn yields a CPS account. A plausible implication is that the monolithic calculus is valuable precisely because it isolates the “one big matching problem” structure in its purest form. That simplicity makes it suitable for semantic derivation, while still supporting open recursion and behavior controlled by observation. The subsequent passage to compositional copatterns then shows that the same semantic story can be refactored to accommodate explicit delimiters, first-class failure, and nested matching without abandoning the original contextual interpretation of copatterns.

Source: https://www.emergentmind.com/topics/calculus-of-monolithic-copatterns