Lectures onType Theory
Control calculi and dependent projection
appendix sectionrules

Control calculi and dependent projection

λK: surface, machine, and runtime typing

The call-by-value continuation calculus extends the simply typed products, sums, 0, 1, naturals, and arrows by A::=ContA,e::=letcc k:ContA in ethrow e to e. Its two new surface rules are

Γ,k:ContAe:A
Γletcc k:ContA in e:A
T-Letcc
Γe1:AΓe2:ContAΓB type
Γthrow e1 to e2:B
T-Throw

Runtime values additionally contain cont(K), and F::=[]ev[][],ev,[]πi[]inl[]inr[]case [] of {inlxe1;inrye2}abortA([])throw [] to ethrow v to [],K::=K;F. States are Ke and Kv. The complete pure roots are KvKv,Ke1e2K;[]e2e1,K;[]e2v1K;v1[]e2,K;(λx.e)[]vKe[v/x],Ke1,e2K;[],e2e1,K;[],e2v1K;v1,[]e2,K;v1,[]v2Kv1,v2,KπieK;πi[]e,K;πi[]v1,v2Kvi,KinleK;inl[]e,K;inl[]vKinlv,KinreK;inr[]e,K;inr[]vKinrv. The three push roots for e1,e2, inle, and inre apply only when their complete subject is not already a value; the corresponding return roots handle value subjects. This is the same value-first side condition used in the chapter. Writing C for the displayed pair of case branches, the remaining pure roots are Kcase e of CK;case [] of Ce,K;case [] of CinlvKe1[v/x],K;case [] of CinrvKe2[v/y],KabortA(e)K;abortA([])e,K;addm[]nK(m+n). There is no return root for the abort frame. The complete control roots are Kletcc k in eKe[cont(K)/k],Kthrow e1 to e2K;throw [] to e2e1,K;throw [] to e2vK;throw v to []e2,K;throw v to []cont(K)Kv.

For a fixed run answer R, frame typing is exactly []e2(AB)B(Re2:A)v[]AB(Rv:AB)[],e2AA×B(Re2:B)v,[]BA×B(Rv:A)πi[]A1×A2Aiinl[]AA+Binr[]BA+BabortB([])0Bcase [] of CA+BCthrow [] to e2AB(Re2:ContA)throw v to []ContAB(Rv:A). The case row requires x:ARe1:C and y:BRe2:C. Stack, internal value, and state typing are

:RR
K-Empty
K:BRF:AB
K;F:AR
K-Push
K:AR
Rcont(K):ContA
T-Cont
K:ARRe:A
RKe
S-Eval
K:ARRv:A
RKv
S-Ret

The fixed-answer CPS signature

The pure target has the same base, product, sum, and empty types and no control forms. Value and computation types are 0v=0,1v=1,Natv=Nat,(A×B)v=Av×Bv,(A+B)v=Av+Bv,(AB)v=AvBc,(ContA)v=Av0,Ac=(Av0)0. Values translate homomorphically, except (λx.e)v=λx.ec,cont(K)v=Khk,vc=λk.kvv. The complete nonvalue term translation is (e1e2)c=λk.e1c(λf.e2c(λa.fak)),e1,e2c=λk.e1c(λa.e2c(λb.ka,b)),(πie)c=λk.ec(λp.k(πip)),(inle)c=λk.ec(λa.k(inla)),(inre)c=λk.ec(λb.k(inrb)),(abortA(e))c=λk:Av0.ec(λz:0.z),(letcc c in e)c=λκ:Av0.(ec[κ/c])κ,(throw e1 to e2)c=λk.e1c(λa.e2c(λc.ca)). For case, the continuation k is passed to the translation of the selected branch. Fix fresh h:Rv0. The complete stack translation is hk=h,(K;[]e)hk=λf.ec(λa.faKhk),(K;v[])hk=λa.vvaKhk,(K;[],e)hk=λa.ec(λb.Khka,b),(K;v,[])hk=λb.Khkvv,b,(K;πi[])hk=λp.Khk(πip),(K;inl[])hk=λa.Khk(inla),(K;inr[])hk=λb.Khk(inrb),(K;abortA([]))hk=λz:0.z,(K;throw [] to e)hk=λa.ec(λc.ca),(K;throw v to [])hk=λc.cvv. The case-frame clause is λs.case s of {inlxe1cKhk;inrye2cKhk}. Finally Keh=ecKhk,Kvh=Khkvv.

The PPS ordered-row core and its four scoped deltas

The common kind, type/effect/row, term, and evaluation-context grammars are κ::=TER,τ::=αTτρτα::κ.τ,ε::=αEεext,ρ::=αRιερ,v::=xλx.e,e::=vee[e],E::=[]EevE[E]. The variable subscripts are metanotational kind tags, and εext ranges over one of the four extension-specific effect forms below. A metavariable σ ranges over an expression of the kind demanded by its judgment. Thus the raw grammar keeps types, single effects, and ordered rows distinct. Rows are ordered. Writing a single effect after the slash abbreviates the row ει. Kinding consists of K-Var, K-Arr, K-All, K-Nil, and K-Cons:

α::κΔ
Δα::κ
K-Var
Δτ1::TΔρ::RΔτ2::T
Δτ1ρτ2::T
K-Arr
Δ,α::κτ::T
Δα::κ.τ::T
K-All
Δι::R
K-Nil
Δε::EΔρ::R
Δερ::R
K-Cons

The term judgment Δ;Γe:τ/ρ is generated by P-Var, P-Lam, P-App, P-Gen, P-Inst, P-Sub, and P-Lift, exactly:

x:τΓ
Δ;Γx:τ/ι
P-Var
Δ;Γ,x:τ1e:τ2/ρ
Δ;Γλx.e:τ1ρτ2/ι
P-Lam
Δ;Γe1:τ1ρτ2/ρΔ;Γe2:τ1/ρ
Δ;Γe1e2:τ2/ρ
P-App
Δ,α::κ;Γe:τ/ιαFV(Γ)
Δ;Γe:α::κ.τ/ι
P-Gen
Δσ::κΔ;Γe:α::κ.τ/ρ
Δ;Γe:τ[σ/α]/ρ
P-Inst
Δτ1<:τ2Δρ1<:ρ2Δ;Γe:τ1/ρ1
Δ;Γe:τ2/ρ2
P-Sub
Δε::EΔ;Γe:τ/ρ
Δ;Γ[e]:τ/ερ
P-Lift

Subtyping has reflexive, contravariant/covariant arrow, universal, nil-row, and same-head row-cons rules. In full:

Δσ<:σ
Sub-Refl
Δτ21<:τ11Δρ1<:ρ2Δτ12<:τ22
Δ(τ11ρ1τ12)<:(τ21ρ2τ22)
Sub-Arr
Δ,α::κτ1<:τ2
Δα::κ.τ1<:α::κ.τ2
Sub-All
Δρ::R
Δι<:ρ
Sub-Nil
Δρ1<:ρ2
Δερ1<:ερ2
Sub-Cons

Core roots are beta and [v]v, closed under E. Freeness starts at 0-free([]), is preserved by application frames, and satisfies n-free(E)(n+1)-free([E]).

The exact deep-handler delta is ε=Δ0.τ1τ2, with rules

Δ,Δ0τ1::TΔ,Δ0τ2::T
ΔΔ0.τ1τ2::E
K-DH
(n+1)-free(E)
n-free(handle E{x,r.eh; y.er})
Free-DH
Δ;Γv:δτ1/ιΔδ::Δ0Δε::E
Δ;Γdo v:δτ2/ε
DH-Do
Δ;Γe:τ/ερΔ,Δ0;Γ,x:τ1,r:τ2ρτreh:τr/ρΔ;Γ,y:τer:τr/ρ
Δ;Γhandle e{x,r.eh; y.er}:τr/ρ
DH-Handle

For 0-free E, its operation root substitutes λz.handle E[z]{x,r.eh; y.er} for r; its return root substitutes the returned value in er.

The exact shift0 delta is ε=Δ0.τ/ρ:

Δ,Δ0τ::TΔ,Δ0ρ::R
ΔΔ0.τ/ρ::E
K-S0
(n+1)-free(E)
n-free(Ex.er)
Free-S0
Δ,Δ0;Γ,k:τρτe:τ/ρ0Δ,Δ0ρ0<:ρΔτ::TΔερ0::R
Δ;Γshift0 k.e:τ/ερ0
S0-Shift
Δδ::Δ0Δ;Γe:τ/εδρΔ;Γ,x:τer:δτ/δρ
Δ;Γex.er:δτ/δρ
S0-Reset

For 0-free E, E[shift0 k.e]x.ere[(λz.E[z]x.er)/k].

The shallow-handler delta is recursive: ε=μα.Δ0.τ1τ2. Put δε=δ[αε]. Its rules are

Δ,α::E,Δ0τ1::TΔ,α::E,Δ0τ2::T
Δε::E
K-SH
Δ;Γv:δετ1/ιΔδ::Δ0Δε::E
Δ;Γdo v:δετ2/ε
SH-Do
Δ;Γe:τ/ερΔ,Δ0;Γ,x:τ1[ε/α],r:τ2[ε/α]ερτeh:τr/ρΔ;Γ,y:τer:τr/ρ
Δ;Γhandle e{x,r.eh; y.er}:τr/ρ
SH-Handle

Its operation root substitutes λz.E[z] for r, without reinstalling the handler.

The control0 delta is ε=μα.Δ0.τ1τ2/ρ:

Δ,α::E,Δ0τ1::TΔ,α::E,Δ0τ2::TΔ,α::E,Δ0ρ::R
Δε::E
K-C0
Δ,Δ0;Γ,k:τερ[ε/α]τ1[ε/α]e:τ2[ε/α]/ρ0Δ,Δ0ρ0<:ρΔτ::TΔερ0::R
Δ;Γcontrol0 k.e:τ/ερ0
C0-Control

For τe=δετ1, τr=δετ2, and ρr=δερ,

Δδ::Δ0Δ;Γe:τe/ερrΔ;Γ,x:τeer:τr/ρr
Δ;Γex.er:τr/ρr
C0-Reset

Its capture root substitutes λz.E[z], omitting the reset. Every handler/reset context lowers the freeness index by one; every capture root requires a 0-free context.

The nonhomomorphic term clauses whose signatures the deltas support are DH(shift0 k.e)=do(λk.DH(e)),DH(ex.er)=handle DH(e){f,r.fr; x.DH(er)},DD(do v)=shift0 k.λh.hDD(v)(λx.kxh),DD(handle e{x,r.eh; y.er})=DD(e)y.λh.DD(er)(λx.λr.DD(eh)),SH(control0 k.e)=do(λk.SH(e)),SH(ex.er)=handle SH(e){f,r.fr; x.SH(er)},SD(do v)=control0 k.λh.hSD(v)k,SD(handle e{x,r.eh; y.er})=SD(e)y.λh.SD(er)(λx.λr.SD(eh)).

For parity, the four single-effect translations are DH(Δ0.τ/ρ)=α::T.Δ0.((αDH(ρ)DH(τ))DH(ρ)DH(τ))α,DD(Δ0.τ1τ2)=α::T,β::R.(Δ0.DD(τ1)(DD(τ2)βα)βα)βα/β,SH(μα.Δ0.τ1τ2/ρ)=μα.β::T.(Δ0.(βαSH(ρ)SH(τ1))SH(ρ)SH(τ2))β. For the reverse shallow clause, put H(a,b1,b2,g):=Δ0.SD(τ1)(SD(τ2)agb1)gb2. Then SD(μα.Δ0.τ1τ2)=μα.β1::T,β2::T,γ::R.β1(H(α,β1,β2,γ)γβ2)/γ. In every displayed Δ0, the quantifier scopes the entire following arrow expression and retains the declared kind of every member of Δ0.

The hypothetical dependent commuting-projection boundary

This is a separate call-by-name calculus, not λK. A,B::=t=ux:Nat.A,t,u::=xnwitpcallcckt,p,q::=arefl(t,p)prfpsubst p qcallcckpthrowkpthrowkt,V::=arefl(t,V). Contexts are sorted: Γ::=Γ,x:NatΓ,a:AΓ,k÷AΓ,k÷Nat. Here k÷A names a proof continuation accepting an A-proof, and k÷Nat names a number continuation. The rules below print these entries as k:¬A and k:Nat for readability; they are continuation names rather than formulas or ordinary functions. Formula formation and the number/proof leaves are

Γ prop
Dep-Bot-F
Γt:NatΓu:Nat
Γt=u prop
Dep-Eq-F
Γ,x:NatA prop
Γx:Nat.A prop
Dep-Ex-F
nN
Γn:Nat
Dep-Nat
x:NatΓ
Γx:Nat
Dep-Var-N
a:AΓ
Γa:A
Dep-Var-P

The exact strong-pair and equality rules are

Γt:NatΓp:A[t/x]
Γ(t,p):x:Nat.A
Dep-Pair
Γp:x:Nat.A
Γwitp:Nat
Dep-Wit
Γp:x:Nat.A
Γprfp:A[witp/x]
Dep-Prf
tu
Γrefl:t=u
Dep-Refl
Γp:t=uΓq:B[t/x]
Γsubst p q:B[u/x]
Dep-Subst

Conversion along congruential formula convertibility is the explicit rule

Γp:AAB
Γp:B
Dep-Conv

Proof and number control have

Γ,k:¬Ap:A
Γcallcckp:A
Dep-Callcc-P
Γ,k:¬Ap:AΓB prop
Γ,k:¬Athrowkp:B
Dep-Throw-P
Γ,k:Natt:Nat
Γcallcckt:Nat
Dep-Callcc-N
Γ,k:Natt:NatΓB prop
Γ,k:Natthrowkt:B
Dep-Throw-N

The assumption k:¬A names a captured proof context accepting A with command answer sort ; k:Nat analogously names a captured number context. They are not lambda-bound function variables and are invoked only by their matching throws. Pair projections, equality substitution, commuting, and vacuity are wit(t,p)t,prf(t,p)p,subst refl pp,wit(callcckp)callcck(wit(p[kwit/k])),callcckuu(kFV(u)). Reduction is closed under both sorts of callcc. The value-restricted variant changes Dep-Wit and Dep-Prf so their premise must be a syntactic V; no soundness theorem beyond that boundary is imported.

The polymorphic continuation counterexample card

For the separate ML assignment card, let CloseΓ(τ) universally quantify exactly ftv(τ)ftv(Γ), and write στ for monotype instantiation. Its complete rules are

Γ(x)τ
Γx:τ
ML-Var
Σ(c)τ
Γc:τ
ML-Const
Γ,x:τ1e:τ2xdom(Γ)
Γλx.e:τ1τ2
ML-Abs
Γe1:τ2τΓe2:τ2
Γe1e2:τ
ML-App
Γe1:τ1Γ,x:CloseΓ(τ1)e2:τ2xdom(Γ)
Γlet x be e1 in e2:τ2
ML-Let

At a fixed answer monotype, its continuation evaluator is generated by

[]vv
val0
[]K[v]aK[]
Kva
val1
K[[]e2]e1ae1 is not a value
Ke1e2a
fn
K[v1[]]e2ae2 is not a value
Kv1e2a
arg
Ke1[v2/x]a
K(λx.e1)v2a
beta
v1 is headed by neither λ nor callcc nor throw
Kv1v2wrong
wrong
K[let x be [] in e2]e1ae1 is not a value
Klet x be e1 in e2a
bind
Ke2[v1/x]a
Klet x be v1 in e2a
sub
KvKa
Kcallcc va
seize
Kva
Kthrow K va
jump

Search the book

Type to search the local edition.