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 variables of data of an undecided shape are weak instead, and aletleaves them alone. 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 a grade, a producer kind; a command isF^w Unit. ral’s returner is Levy’sF Awith an atomic annotation:F^p Aproduces a value andF^w Unitproduces output and nothing else. A command — an external, a builtin that writes, a handler arm standing in for one — is the latter, so{ echo hi }is{Command}and{ 'hi' }is{Returns String}. The grade says how a result is produced, not whether anything is written, so{ echo pre; return 5 }isF^p Int. Thatlet x = hostnamebinds the texthostnamewrites is the one coercioncap : F^w Unit ⇝ F^p String, which the checker inserts where a value is demanded of a command (graded-f, types). Levy’s adjunction is unchanged; grades are unified like type variables.- 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 a stage feeds the next by writing —Γ ⊢ M : F^ε UnitandΓ ⊢ N : F^ε' BgiveΓ ⊢ M | N : F^ε' B, the value the final stage’s. What the combinator does is operational: it connectsM’s stdout toN’s stdin with an operating-system pipe. A ral-written stage runs its own CEK machine on an OS thread, in a childShellseeded from the parent’s session; only an external command is a process, and only externals are members of the pipeline’s process group, which the parent shell itself is not (pipelines, stages-are-threads). 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.