Call-by-push-value — the substrate, taken as surface design
Levy, Call-by-Push-Value: A Subsuming Paradigm, TLCA 1999; the 2003 book Call-by-Push-Value: A Functional/Imperative Synthesis.
ral is CBPV in the wild: Levy’s calculus is not just its IR but its surface design. “A value is, a computation does” is realised as a user-facing discipline — data never executes, and only a forced command in head position touches the world (cbpv, ir-pure-cbpv).
What ral takes whole
- The two sorts, surfaced as the two sigils. Values vs computations is
Levy’s split; ral exposes it as
$name(dereference, never forces) against head position (force). The thunk{M}isU; a command returningAis anF; blocks are literallyU(A → B)— the CBV image of functions, written honestly. - Sequencing is
to, and it earns its keep in inference. ral’sletover a command is Levy’sM to x. N. Generalisation atBindneeds no value restriction precisely because CBPV sequences the effect before binding — the thing generalised is always a value whose effect has already happened (types). The substrate does real type-theoretic work. - The subsumption is live, not historical. Eager application is the
call-by-value image; passing a
{M}thunk recovers a call-by-name call site term-by-term. Both disciplines are expressible and neither is baked in — which is Levy’s theorem used as a language-design budget. - The machine is the CK reading, now literally a CEK machine. ral’s
evaluator steps a focus ⟨M, E⟩ against a stack of frames, each frame
carrying the environment it resumes under
(evaluator-machine). A tail call pushes no
frame — β binds the argument into the closure’s own environment and puts
the body in focus, so depth is exactly
stack.len(). That is Levy’s jumping intuition — calling a procedure is a jump, and returning is also a jump — with the stack discipline enforced by the module’s two doors,evaluateandapply, rather than by a calculus of stacks.
Divergences (extensions, mostly)
Fcarries one annotation, and it is not a grade. ral’s returner isF[ρ] A, whereρ ∈ {Value, Bytes}says which of a computation’s two products a value boundary observes — the returnedA, or the stdout it wrote (types). It bounds no effect, licenses nothing, and does not multiply along a bind:M to x. Nsimply takesN’s route. The formation ruleρ = Bytes ⇒ A = Unitis the whole of its theory. Strip the annotation and what is left is Levy’s calculus unchanged (pipes-are-positional-byte-wires).- The pipe is a new computation combinator, and it is not a typing fact.
CBPV composes computations by sequencing and application only. ral adds
|, whose static rule says just that both sides are computations —Γ ⊢ M : F[ρ] AandΓ ⊢ N : F[σ] BgiveΓ ⊢ M | N : F[σ] B. What the combinator does is operational: it connectsM’s stdout toN’s stdin with an operating-system pipe, discardsM’s returned value, and runs both in one process group (pipelines). It is not a CBPV connective; it is exactly where ral is a shell rather than a λ-calculus, and the honest reading is that the shell’s one composition operator lives outside the calculus rather than being encoded into it. - No computation products. ral’s computation types are
F[ρ] AandA → C, full stop; Levy’sΠᵢ Bᵢis absent. Where it would be used, a record of thunks — a value product ofUs — serves. - The effect interface is fixed. Levy’s calculus is effect-agnostic; ral pins the operation signature at the external-command boundary (syscalls-are-effects), the Plotkin–Power layer over CBPV (handlers-of-algebraic-effects).
What ral could borrow
- The proof vocabulary, when SPEC §4 is formalised. Levy’s stack machine
and the adjunction models with stacks are the off-the-shelf framework in
which the frame stack and
Settled<Value>become statements about stacks, and the machine’s correctness a simulation result — the jumping-semantics paper is the bridge. - The βη-theory for the pure fragment. cbpv’s “equational reasoning in the pure fragment” can cite CBPV’s equational theory verbatim rather than re-deriving it.
Cite: Levy, Call-by-Push-Value: A Subsuming Paradigm (TLCA 1999, Zotero
EBD23DBT); Call-by-Push-Value: A Functional/Imperative Synthesis (2003,
Zotero GMGNPJTX); Jumping Semantics for Call-By-Push-Value (Zotero
83ADMPBG); Adjunction Models for Call-By-Push-Value with Stacks (Zotero
3JTC3NB8). ral side: RATIONALE §“Values and commands”; docs/SPEC.md §2,
§5.