cubical-transport-hott-lean4/CubicalTransport/Value.lean
Maximus Gorog f27211f73f REL1 foundation: schema-based inductive + HIT CTypes (Lean side)
Adds schema-based inductive type encoding to the engine, supporting both
plain inductives (Nat, List, Bool) and HITs (S¹, propositional truncation,
suspensions) via a single CTypeSchema/CtorSpec/CTypeArg structure.

New CType constructor:
  - .ind (S : CTypeSchema) (params : List CType)

New CTerm constructors:
  - .dimExpr  (r : DimExpr)
  - .ctor     (S, ctorName, params, args)
  - .indElim  (S, params, motive, branches, target)

New CVal constructors:
  - .vctor    (S, ctorName, params, evaluatedArgs)
  - .vdimExpr (DimExpr)

New CNeu constructor:
  - .nIndElim (S, params, motive, branches, neuTarget)

Five-way mutual block in Syntax.lean (CType, CTerm, CTypeArg, CtorSpec,
CTypeSchema) with Repr derivation post-hoc.  Tag layout per
docs/INDUCTIVE_TYPES.md §6: old tags preserved (no shifting).  Existing
62/62 smoke + property tests pass unchanged through Rust.

Substitution / dim-absent / endpoint handling:
  Subst.lean      — substDim, substDimExpr, equation lemmas,
                    substDim_eq_substDimExpr (mutual with .params helpers).
  DimLine.lean    — CTerm.dimAbsent + CType.dimAbsent (mutual w/ helpers
                    for list / branches / params).  Plus all five
                    auxiliary mutual blocks: substDim_absent_aux,
                    substDimExpr_absent_aux, dimAbsent_after_substDim_aux,
                    substDim_comm_aux — for both CTerm and CType.

Eval.lean: ctor → vctor (eval'd args); indElim β-reduces on canonical
vctor target via vApp chain over branch body, otherwise stuck via
.nIndElim; dimExpr → vdimExpr.  Path-ctor boundary firing and
recursive-arg IH wiring marked TODO REL1.1 (β-reduction works for
non-recursive ctors today).

Readback.lean: vctor → .ctor, vdimExpr → .dimExpr, nIndElim → .indElim.

FFITest.lean: cvalSummary / ctermSummary extended with new constructor
arms.

Topolei (sibling repo) has not yet been migrated — see
docs/INDUCTIVE_TYPES.md §9.1 for the per-file impact map.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 15:09:39 -06:00

227 lines
12 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Topolei.Cubical.Value
=====================
Weak-head normal forms for the cubical calculus (cells-spec §5.4, Phase 1
Week 2).
Named-variable adaptation: our `CTerm` uses `String` binders rather than
de Bruijn indices, so `Env` is a name-keyed association list instead of an
`Array`. The three inductives (`Env`, `CVal`, `CNeu`) are mutually
recursive: `CVal` contains closures (which capture their `Env`), `CNeu`
(stuck terms) carries already-evaluated sub-values, and `Env` stores `CVal`s.
Coverage matches the cells-spec's "λ-calculus fragment" milestone:
· function abstractions and applications (`vlam`/`napp`)
· dimension abstractions and applications (`vplam`/`npapp`)
· transport and composition as *stuck* values (`ntransp`/`ncomp`) —
actual reduction rules arrive in Weeks 34 (`Transport.lean`/`Comp.lean`).
No type-level values yet: `CType` remains syntactic because types are not
evaluated in the λ-fragment. When we add the Π/Σ cases of transport the
evaluator will grow a companion `evalType` returning a `VType`.
-/
import CubicalTransport.Syntax
mutual
/-- Name-keyed environment: a cons-list of `(name, value)` bindings. The
most-recently-extended binding shadows earlier ones of the same name. -/
inductive CEnv : Type where
| nil : CEnv
| cons : String → CVal → CEnv → CEnv
deriving Inhabited
/-- Weak-head normal-form values. -/
inductive CVal : Type where
/-- Function closure `(λ x. body)` with captured environment. -/
| vlam : CEnv → String → CTerm → CVal
/-- Dimension-abstraction closure `(⟨i⟩ body)` with captured environment. -/
| vplam : CEnv → DimVar → CTerm → CVal
/-- Embedded neutral term — a stuck computation. -/
| vneu : CNeu → CVal
/-- A *transported function value*: the result of
`transp^i (pi domA codA) φ f` — the full CCHM Π rule, supporting
both varying domain and varying codomain. Stores `i`, the domain
type, the codomain type, the face formula, and the underlying
function value `f`.
When applied to an argument `y : A(1)`, it reduces per the CCHM
Π rule:
`vApp (.vTranspFun i domA codA φ f) y =`
` vTransp i codA φ (vApp f (vTranspInv i domA φ y))`
That is:
1. Inversely transport `y` through `domA` to get `y' : A(0)`.
2. Apply `f` to `y'` to get a value in `B(0)`.
3. Forward-transport the result through `codA` to land in `B(1)`.
When `domA` is absent from `i`, step 1 reduces to identity (via
`vTranspInv_const`), recovering the earlier const-domain form. -/
| vTranspFun : DimVar → CType → CType → FaceFormula → CVal → CVal
/-- A *composed function value*: the result of
`hcomp (pi domA codA) φ tube base`. Homogeneous composition on a
Π type reduces pointwise: applied to `y : A`, it returns
`hcomp codA φ (λj. (tube@j) y) (base y)`. Stores only `codA`
(there is no inverse transport through `domA` in homogeneous
composition, so `domA` plays no role in the reduction), the face
formula, the tube, and the base function. -/
| vHCompFun : CType → FaceFormula → CVal → CVal → CVal
/-- A *point-wise applied tube*: represents `λj. (tube @ j) arg` as
a dim-abstraction value. Produced by `vApp` on `vHCompFun` when
the outer hcomp's tube needs to be threaded into the inner hcomp
on the codomain. Reduces under `vPApp r` to
`vApp (vPApp tube r) arg`. -/
| vTubeApp : CVal → CVal → CVal
/-- A *heterogeneous-composition function value*: the result of
`comp^i (Π domA codA) φ u u₀` at the value level. Stores env,
line binder `i`, both CType halves, face, and tube `u` + base
`u₀` as CTerms (so the CCHM reduction can construct term-level
comp/transport expressions referencing them).
Applied to `y : A(1)`, it reduces per CCHM Π hetero comp:
1. Construct the *fill* `y_at_j : A(j)` — a partial transport
of `y` backwards along the A-line.
2. Inner tube: `(u @ i) (y_at_i)` — apply u's tube pointwise.
3. Inner base: `u₀ (y_at_0)` — apply base to the "inverse-transport"
endpoint of the fill.
4. Build a new `comp^i codA φ <inner tube> <inner base>` and
evaluate.
When `domA` is absent from `i`, the fill degenerates (constant
line ⇒ identity transport), so `y_at_i = y_at_0 = y` and the
reduction specialises to the simpler const-domain form. -/
| vCompFun : CEnv → DimVar → CType → CType → FaceFormula →
CTerm → CTerm → CVal
/-- A *path-transport value*: the result of
`transp^i (Path A(i) a(i) b(i)) φ p` at the value level.
Stores the environment where `a`, `b`, `p` were meaningful, the
line binder `i`, the path's base type `A` (may vary in `i`), the
left/right endpoint CTerms, the face formula, and the path term
`p` as a CTerm (so a later `.papp p r` term can be constructed
for the CCHM multi-clause reduction).
Reductions on `vPApp`:
· At `.zero` → `eval env (a.substDim i .one)` (= a(1)).
· At `.one` → `eval env (b.substDim i .one)` (= b(1)).
· At generic `r` → evaluate the CCHM compN term
`comp^i A [φ ↦ p@r, (r=0) ↦ a, (r=1) ↦ b] (p@r)` via
`vCompNAtTerm`. This genuinely unsticks: when `r` has a
resolved endpoint, the corresponding clause fires. -/
| vPathTransp : CEnv → DimVar → CType → CTerm → CTerm → FaceFormula →
CTerm → CVal
/-- A Σ pair value: both components already evaluated. `vFst` and
`vSnd` (defined in `Eval.lean`) project out the components; on a
`vpair` they reduce component-wise, on a `vneu` they produce a
stuck `.nfst`/`.nsnd` neutral. -/
| vpair : CVal → CVal → CVal
/-- Schema constructor application — fully-evaluated, canonical
constructor of an inductive (or higher-inductive) type (REL1).
`vctor S c params args` carries:
- `S : CTypeSchema` — the schema this constructor belongs to.
- `c : String` — the constructor's name.
- `params : List CType` — the type parameters at which the
inductive was instantiated.
- `args : List CVal` — already-evaluated argument values.
For path constructors, when a `.dim`-typed arg lands on a face
in the constructor's boundary system, eval fires the boundary
clause and never produces a `vctor` — so a `vctor` represents
a value that is *not* on a boundary face. -/
| vctor : CTypeSchema → String → List CType → List CVal → CVal
/-- Lifted dimension-expression value (REL1). Produced by
`eval env (.dimExpr r)`; consumed by path-constructor face
dispatch and by `vPApp` when its left operand is a `vplam`
whose argument is a `.dimExpr`. -/
| vdimExpr : DimExpr → CVal
/-- Neutral (stuck) terms. Each constructor corresponds to a
λ-calculus or cubical elimination whose principal argument is itself
neutral, so the elimination cannot proceed. -/
inductive CNeu : Type where
/-- A free variable (name not bound in the current environment). -/
| nvar : String → CNeu
/-- Stuck function application. -/
| napp : CNeu → CVal → CNeu
/-- Stuck dimension application. -/
| npapp : CNeu → DimExpr → CNeu
/-- Transport with an already-evaluated argument. The `CType` and
`FaceFormula` are kept syntactic for now; a later pass will evaluate
them and destructure per type-former. -/
| ntransp : DimVar → CType → FaceFormula → CVal → CNeu
/-- Heterogeneous composition (varying line) with already-evaluated
system body and base. Used for `.comp` terms whose type varies
along the dimension and whose reduction hasn't been pinned by
one of the special-case rules (`.top`, `.bot`, constant line). -/
| ncomp : DimVar → CType → FaceFormula → CVal → CVal → CNeu
/-- Homogeneous composition (fixed type) with already-evaluated tube
and base. Produced by `vHCompValue` when the type isn't a `.pi`
(Π hcomp reduces to `vHCompFun` instead of a neutral). -/
| nhcomp : CType → FaceFormula → CVal → CVal → CNeu
/-- A stuck multi-clause heterogeneous composition. Produced by
`vCompNAtTerm` when none of its reducing arms apply (e.g. every
clause's face is neither trivially satisfied nor trivially empty,
and the line type genuinely varies). Preserves env, binder,
line type, the evaluated clause list, and the evaluated base. -/
| ncompN : CEnv → DimVar → CType →
List (FaceFormula × CVal) → CVal → CNeu
/-- A stuck glue introduction. Produced by `eval` on `.glueIn φ t a`
when `φ` is neither `.top` (→ `t`) nor `.bot` (→ `a`). Preserves
the face formula and both face-on / face-off evaluated sub-values
so that later dim-substitution can unstick if the face resolves. -/
| nglueIn : FaceFormula → CVal → CVal → CNeu
/-- A stuck unglue. Produced by `eval` on `.unglue φ f g` when `φ` is
not `.top` (→ `vApp f g`) and `g` is not a glued value whose face
is `.bot` (→ `g`). Preserves the face formula, the forward-map
value `f`, and the argument value `g`. -/
| nunglue : FaceFormula → CVal → CVal → CNeu
/-- A stuck first projection. Produced by `vFst` when its argument
is itself a neutral (i.e. not a `vpair`). -/
| nfst : CNeu → CNeu
/-- A stuck second projection. Produced by `vSnd` on a neutral. -/
| nsnd : CNeu → CNeu
/-- A stuck inductive eliminator (REL1). Produced by `eval`'s
`.indElim` arm when the target evaluates to a neutral (or a
non-`vctor` value). Preserves the schema, parameters, motive,
evaluated branches, and the underlying neutral target so that
later substitution / unstucking can fire the matching branch. -/
| nIndElim : CTypeSchema → List CType → CVal →
List (String × CVal) → CNeu → CNeu
end
-- Inhabited instances — needed so `partial def` evaluators can be elaborated
-- (Lean's partial-fixpoint compilation requires a default value for divergence).
instance : Inhabited CNeu := ⟨.nvar "⊥"⟩
instance : Inhabited CVal := ⟨.vneu default⟩
namespace CEnv
/-- Look up a variable name; returns `none` if the name is free. -/
def lookup : CEnv → String → Option CVal
| .nil, _ => none
| .cons n v rest, x => if x = n then some v else rest.lookup x
/-- Extend an environment with a new `(name, value)` binding. -/
def extend (env : CEnv) (x : String) (v : CVal) : CEnv :=
.cons x v env
@[simp] theorem lookup_nil (x : String) : CEnv.lookup .nil x = none := rfl
@[simp] theorem lookup_cons_hit (x : String) (v : CVal) (rest : CEnv) :
(CEnv.cons x v rest).lookup x = some v := by
simp [lookup]
theorem lookup_cons_miss (x y : String) (v : CVal) (rest : CEnv) (h : y ≠ x) :
(CEnv.cons x v rest).lookup y = rest.lookup y := by
simp [lookup, if_neg h]
@[simp] theorem extend_lookup_hit (env : CEnv) (x : String) (v : CVal) :
(env.extend x v).lookup x = some v := by
simp [extend]
theorem extend_lookup_miss (env : CEnv) (x y : String) (v : CVal) (h : y ≠ x) :
(env.extend x v).lookup y = env.lookup y := by
simp [extend, lookup, if_neg h]
end CEnv