Desc-interp
desc.nix encodes FreeFx as plus pureSummand impureSummand;
continuations live in an FTCQueue value (Kiselyov & Ishii) rather
than meta-level Nix functions. kernel.nix mirrors fx.kernel's
pure/send/bind; bind snocs into the Impure summand's
queue without recursing on the μ-tree. trampoline.nix drives
programs via builtins.genericClosure at O(1) host stack depth.
Handler shortcut layering
Each canonical handler op admits a partial-evaluation residual
that bypasses kernel vApp per Impure step. Soundness splits:
- kernel-side (
effects/*-shortcut-laws.nix):H.refllemmahandle_X op s ≡_kernel mkResumeAt … r s(resp.mkAbortAt) certifying the per-op rewrite under ι+β. - emitter-side (
extract.nix): per-primitive Val-conv testeval (HOAS witness) ≡_Val extract (Primitive …). Sugars (Resume/Abort/PairRaw) fold into primitives. - composed-side (
compose.nix+composed-shortcut.nix+composed-shortcut-laws.nix):composeHandlersover UniRet closes the algebra under+. Six lemmas chaincomposeHandlersInl/InrLemmawith per-effect uniform-shortcut lemmas;composedHandlerShortcutmirrors the kernel-composed path by direct Val construction.
Adding a new effect with a handler shortcut
Recipe — apply in order:
Identify canonical RHS shapes. Reduce
handle_X op sper constructor via ι+β. Each canonical op should normalise tomkResumeAt … r sormkAbortAt … v s(or a bareH.pair _ _outside the UniRet shape).Extend
extract.nixonly if needed. Existing sugars cover the UniRet and bare-pair shapes; primitives (DescCon,BootInl,BootInr,Pair,Tt,BootRefl) suffice for anything else. Add a sugar only when a non-trivial shape repeats across multiple effects.Write
effects/x-shortcut-laws.nix. OneH.refllemma per canonical op assertinghandle_X op s ≡_kernel mkXAt …. Mirroreffects/state-shortcut-laws.nix'swithPrefix/lamPrefixhelper layout. IfuniformOf_Xdiffers fromhandle_X(error's three strategies), addeffects/x-uniform-shortcut-laws.nixtoo.Wire
handlerShortcutinatType. Pre-compute metadata Vals (leftSig,rightSig,sumDescVal) once per instantiation; inhandlerShortcut op stateVal, dispatch onop._opTagand returnextract (Resume …)/extract (Abort …)/extract (PairRaw …). Smart constructors tag canonical ops via_opTag = "<effect>-<op>". IfuniformOf_Xis needed for composition, exposeuniformOfShort(oruniformOfShortAt Aif A varies post-atType).Add parity tests in
trampoline.nix. For each canonical op, comparerunX { handler; dispatch; }vsrunX { handler; dispatch; handlerShortcut; }viafx.tc.conv.conv 0on both.valueand.state. For ops that abort with a Nix throw (strict-style), force.state.tagunderbuiltins.tryEvaland assert both paths trip the throw.
Composition with another effect via composeHandlers reuses the
per-effect uniformOfShort plus composedHandlerShortcut H_short_A
H_short_B metaFor; soundness is anchored kernel-side by
composed-shortcut-laws.nix without any per-effect-pair work.
Sub-namespaces
composecompose-lawscomposed-shortcutcomposed-shortcut-lawsdescdescind-lawseffectsextractkerneltrampoline
Source
src/experimental/desc-interp/compat.nixsrc/experimental/desc-interp/compose-laws.nixsrc/experimental/desc-interp/compose.nixsrc/experimental/desc-interp/composed-shortcut-laws.nixsrc/experimental/desc-interp/composed-shortcut.nixsrc/experimental/desc-interp/desc.nixsrc/experimental/desc-interp/descind-laws.nixsrc/experimental/desc-interp/extract.nixsrc/experimental/desc-interp/kernel.nixsrc/experimental/desc-interp/trampoline.nix