cubical-transport-hott-lean4/CubicalTransport/Reflect.lean
Maximus Gorog b9ca1d8875
Some checks are pending
Lean Action CI / build (push) Waiting to run
Modal cascade Phase 1: Syntax + Lean engine cascade
Per THEORY.md §3.1: cubical-native modal type formers as the engine
support layer for the cohesive modality triple (ʃ ⊣ ♭ ⊣ ♯).

CType (3 level-preserving formers):
  · CType.flat / .sharp / .shape : {ℓ} → CType ℓ → CType ℓ

CTerm (6 — three intros + three elims, modelled on .glueIn / .unglue):
  · CTerm.flatIntro / .sharpIntro / .shapeIntro  : CTerm → CTerm
  · CTerm.flatElim  / .sharpElim  / .shapeElim   : CTerm → CTerm → CTerm

Cascade: Syntax (constructors + SkeletalCType + skeleton + substDim);
DecEq (beq arms); Subst (substDim / substDimExpr + 6 rfl theorems);
DimLine (cascade through 8 dim-absent / dim-substitution lemma families);
Value (3 vIntro CVal + 3 nElim CNeu); Eval (β-reduction axioms +
stuck-neutral propagation, "marker neutral" idiom from vFst/vSnd
preserved); Readback (3 vIntro + 3 nElim arms with axioms); Typing
(6 HasType cases — bare recursion-principle shape; modal cohesion
dependent-motive form deferred to Phase 3); Reflect (3 reflectCType + 6
reflectCTerm + 3 reifyCType with level-coherence discharge + 6
reifyCTerm); Question (6 modal arms + 6 IsModalLine classifier
predicates with their Decidable instances); FFITest (cval/cterm
summary arms).

No Rust changes (Phase 2).  No Modal.lean module (Phase 3).  No
Crisp / CContext.crispVar / cohesive_triple theorems (Phase 3).

Build: lake build (48 jobs) + lake build CubicalTransport (42 jobs) PASS.
+664 lines across 11 files, 0 removed, 0 new sorries.

Honest deferrals documented:
  · Modal type-formers do not yet reduce under transport/comp; the
    match A blocks have wildcards so transp i (flat A) φ t produces a
    stuck ntransp neutral (correct under current axiom set; cohesion-
    driven reductions land in Phase 3).
  · HasType.flatElim et al carry the bare recursion-principle shape;
    the cohesive-HoTT-correct dependent-motive form requires the modal
    predicate lattice from Phase 3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:22:03 -06:00

1544 lines
62 KiB
Text
Raw 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.

/-
CubicalTransport.Reflect
========================
Reflection metaprogramming layer (THEORY.md §0.9).
Bidirectional bridge between the engine's first-class CTerm / CType
inductives and Lean's tactic-facing `Lean.Expr` representation.
## What this module exports
· `reflectULevel : ULevel → MetaM Expr`
· `reflectCType : ∀ { : ULevel}, CType → MetaM Expr`
· `reflectCTerm : CTerm → MetaM Expr`
· `reifyULevel : Expr → MetaM (Option ULevel)`
· `reifyCType : Expr → MetaM (Option (Σ : ULevel, CType ))`
· `reifyCTerm : Expr → MetaM (Option CTerm)`
· `Contract.register : Lean.Name → ContractEntry → IO Unit`
· `Contract.lookupByName : Lean.Name → IO (Option ContractEntry)`
· `Contract.allRegistered : IO (List Lean.Name)`
· Round-trip theorems on the image of the reflection functions.
## Design
· `reflectCType` produces a Lean `Expr` that, when elaborated in
a context with `CubicalTransport` open, evaluates back to the
original CType. Each constructor maps to a fully-applied
`Expr.app`-tree over its constructor's `Lean.Name`, with every
implicit `{ : ULevel}` argument made explicit (Expr-level
construction is always fully explicit).
· `reflectCTerm` is similar.
· The mutual nature of CType / CTerm is reflected at the
metaprogramming level: `reflectCType` calls `reflectCTerm` on
its CTerm sub-payloads (path endpoints, glue equiv components),
and `reflectCTerm` calls `reflectCType` on its CType payloads
(transp / comp / code arguments).
· `reify*` are the inverses, returning `Option` because not every
`Expr` is a valid encoding. `reifyULevel` is fully discharged
structurally; `reifyCType` and `reifyCTerm` have their full
per-constructor inverse pending the `Expr`-pattern-matching
scaffolding (annotated below).
· The Contract registry is an
`IO.Ref (Std.HashMap Lean.Name ContractEntry)`.
Contracts register themselves in their defining module's
`initialize` block; tactics and other consumers look them up
by name.
## Coupling note (Contract module)
The `Contract` type itself is `def Contract ( : ULevel) : Type :=
CType → CTerm` — exported by `CubicalTransport.Contract`. This
module re-exports the same definition locally (as an `abbrev` —
definitionally equal to the upstream) to avoid a circular
dependency: contracts in `CubicalTransport.Contract` will register
themselves into the registry exposed here, so `Contract` must
import `Reflect`, not the other way around. The two spellings
unify by reducibility, so registering a `Contract.Contract` value
via `Reflect.Contract.register` typechecks without any conversion.
-/
import Lean
import CubicalTransport.Syntax
import CubicalTransport.Inductive
import CubicalTransport.Typing
namespace CubicalTransport.Reflect
open Lean Meta
/-- Local re-export of the Contract type; definitionally equal to
`CubicalTransport.Contract.Contract`. -/
abbrev Contract ( : ULevel) : Type := CType → CTerm
-- ── §1. Reflection: ULevel → Expr ──────────────────────────────────────────
/-- Reflect a `ULevel` to its `Lean.Expr` encoding. Walks the
inductive's two constructors directly; the produced Expr is
`@ULevel.zero` or `@ULevel.succ <recurse>`. -/
partial def reflectULevel : ULevel → MetaM Expr
| .zero => return mkConst ``ULevel.zero
| .succ n => do
let ne ← reflectULevel n
return mkApp (mkConst ``ULevel.succ) ne
-- ── §2. Reflection helpers (DimVar / DimExpr / FaceFormula / schema) ─────
/-- Reflect a `DimVar` (a single-field structure carrying `name : String`). -/
partial def reflectDimVar : DimVar → MetaM Expr
| ⟨name⟩ => return mkApp (mkConst ``DimVar.mk) (mkStrLit name)
/-- Reflect a `DimExpr` (the free de Morgan algebra on dim variables).
Walks all six constructors: `.zero`, `.one`, `.var i`, `.inv r`,
`.meet r s`, `.join r s`. -/
partial def reflectDimExpr : DimExpr → MetaM Expr
| .zero => return mkConst ``DimExpr.zero
| .one => return mkConst ``DimExpr.one
| .var i => do
let iE ← reflectDimVar i
return mkApp (mkConst ``DimExpr.var) iE
| .inv r => do
let rE ← reflectDimExpr r
return mkApp (mkConst ``DimExpr.inv) rE
| .meet r s => do
let rE ← reflectDimExpr r
let sE ← reflectDimExpr s
return mkAppN (mkConst ``DimExpr.meet) #[rE, sE]
| .join r s => do
let rE ← reflectDimExpr r
let sE ← reflectDimExpr s
return mkAppN (mkConst ``DimExpr.join) #[rE, sE]
/-- Reflect a `FaceFormula`. Walks all six constructors:
`.bot`, `.top`, `.eq0 i`, `.eq1 i`, `.meet ϕ ψ`, `.join ϕ ψ`. -/
partial def reflectFaceFormula : FaceFormula → MetaM Expr
| .bot => return mkConst ``FaceFormula.bot
| .top => return mkConst ``FaceFormula.top
| .eq0 i => do
let iE ← reflectDimVar i
return mkApp (mkConst ``FaceFormula.eq0) iE
| .eq1 i => do
let iE ← reflectDimVar i
return mkApp (mkConst ``FaceFormula.eq1) iE
| .meet a b => do
let aE ← reflectFaceFormula a
let bE ← reflectFaceFormula b
return mkAppN (mkConst ``FaceFormula.meet) #[aE, bE]
| .join a b => do
let aE ← reflectFaceFormula a
let bE ← reflectFaceFormula b
return mkAppN (mkConst ``FaceFormula.join) #[aE, bE]
-- ── §3. Reflection: CType / CTerm → Expr ──────────────────────────────────
/-- The `Expr` for the family `fun : ULevel => CType `, used as
the implicit family argument of `Sigma.mk` when reflecting
heterogeneous-level CType lists. Built once via the bound-
variable `Expr.bvar 0` under a single λ-binder. -/
def cTypeFamilyExpr : Expr :=
.lam ` (mkConst ``ULevel)
(mkApp (mkConst ``CType) (.bvar 0))
.default
/-- The `Expr` for the type `Σ : ULevel, CType `. -/
def cTypeSigmaExpr : Expr :=
mkAppN (mkConst ``Sigma [Level.zero, Level.zero])
#[mkConst ``ULevel, cTypeFamilyExpr]
/-- Build the `Expr` for `@Sigma.mk ULevel (fun => CType ) E AE`. -/
def mkSigmaULevelCType (E : Expr) (AE : Expr) : Expr :=
mkAppN (mkConst ``Sigma.mk [Level.zero, Level.zero])
#[mkConst ``ULevel, cTypeFamilyExpr, E, AE]
mutual
/-- Reflect a `CType` (at any universe level) to a `Lean.Expr`.
The level `` is itself reflected and emitted as the explicit
implicit-position argument of the constructor in the Expr-form. -/
partial def reflectCType : { : ULevel} → CType → MetaM Expr := fun {} t =>
match t with
| .univ =>
-- `@CType.univ _inner` where = _inner.succ. We need
-- _inner — recover it from the result level : .succ _inner
-- by deconstructing . When `t = .univ`, we have = _inner.succ,
-- so _inner is the predecessor.
match with
| .succ _inner => do
let _innerE ← reflectULevel _inner
return mkApp (mkConst ``CType.univ) _innerE
| .zero =>
-- Unreachable: `.univ : CType (.succ)` so ≠ .zero.
-- Discharge by emitting a dummy that will never trigger
-- — but to keep totality, we still produce an Expr.
-- This branch is genuinely dead by typing.
return mkApp (mkConst ``CType.univ) (mkConst ``ULevel.zero)
| @CType.pi _a _b var A B => do
let _aE ← reflectULevel _a
let _bE ← reflectULevel _b
let varE := mkStrLit var
let AE ← reflectCType A
let BE ← reflectCType B
return mkAppN (mkConst ``CType.pi) #[_aE, _bE, varE, AE, BE]
| @CType.sigma _a _b var A B => do
let _aE ← reflectULevel _a
let _bE ← reflectULevel _b
let varE := mkStrLit var
let AE ← reflectCType A
let BE ← reflectCType B
return mkAppN (mkConst ``CType.sigma) #[_aE, _bE, varE, AE, BE]
| .path A a b => do
let E ← reflectULevel
let AE ← reflectCType A
let aE ← reflectCTerm a
let bE ← reflectCTerm b
return mkAppN (mkConst ``CType.path) #[E, AE, aE, bE]
| .glue φ T f fInv sec ret coh A => do
let E ← reflectULevel
let φE ← reflectFaceFormula φ
let TE ← reflectCType T
let fE ← reflectCTerm f
let fInvE ← reflectCTerm fInv
let secE ← reflectCTerm sec
let retE ← reflectCTerm ret
let cohE ← reflectCTerm coh
let AE ← reflectCType A
return mkAppN (mkConst ``CType.glue)
#[E, φE, TE, fE, fInvE, secE, retE, cohE, AE]
| .ind S params => do
let E ← reflectULevel
let SE ← reflectCTypeSchema S
let paramsE ← reflectCTypeAnyList params
return mkAppN (mkConst ``CType.ind) #[E, SE, paramsE]
| .interval =>
return mkConst ``CType.interval
| .lift A => do
-- `.lift A : CType (_inner.succ)`. Same predecessor-extraction
-- as `.univ`: ` = _inner.succ`, so _inner is `.pred`. We
-- recurse on A directly (Lean infers the inner level).
match with
| .succ _inner => do
let _innerE ← reflectULevel _inner
let AE ← reflectCType A
return mkAppN (mkConst ``CType.lift) #[_innerE, AE]
| .zero =>
-- Unreachable: `.lift A : CType (_inner.succ)`.
let AE ← reflectCType A
return mkAppN (mkConst ``CType.lift) #[mkConst ``ULevel.zero, AE]
| .El P => do
let E ← reflectULevel
let PE ← reflectCTerm P
return mkAppN (mkConst ``CType.El) #[E, PE]
| .flat A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.flat) #[E, AE]
| .sharp A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.sharp) #[E, AE]
| .shape A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CType.shape) #[E, AE]
/-- Reflect a `CTerm` to a `Lean.Expr`. -/
partial def reflectCTerm : CTerm → MetaM Expr
| .var x => return mkApp (mkConst ``CTerm.var) (mkStrLit x)
| .lam x t => do
let te ← reflectCTerm t
return mkAppN (mkConst ``CTerm.lam) #[mkStrLit x, te]
| .app f a => do
let fe ← reflectCTerm f
let ae ← reflectCTerm a
return mkAppN (mkConst ``CTerm.app) #[fe, ae]
| .plam i t => do
let ie ← reflectDimVar i
let te ← reflectCTerm t
return mkAppN (mkConst ``CTerm.plam) #[ie, te]
| .papp t r => do
let te ← reflectCTerm t
let re ← reflectDimExpr r
return mkAppN (mkConst ``CTerm.papp) #[te, re]
| @CTerm.transp i A φ t => do
let ie ← reflectDimVar i
let E ← reflectULevel
let AE ← reflectCType A
let φE ← reflectFaceFormula φ
let te ← reflectCTerm t
return mkAppN (mkConst ``CTerm.transp) #[ie, E, AE, φE, te]
| @CTerm.comp i A φ u t => do
let ie ← reflectDimVar i
let E ← reflectULevel
let AE ← reflectCType A
let φE ← reflectFaceFormula φ
let ue ← reflectCTerm u
let te ← reflectCTerm t
return mkAppN (mkConst ``CTerm.comp) #[ie, E, AE, φE, ue, te]
| @CTerm.compN i A clauses t => do
let ie ← reflectDimVar i
let E ← reflectULevel
let AE ← reflectCType A
let clausesE ← reflectClausesList clauses
let te ← reflectCTerm t
return mkAppN (mkConst ``CTerm.compN) #[ie, E, AE, clausesE, te]
| .glueIn φ t a => do
let φE ← reflectFaceFormula φ
let te ← reflectCTerm t
let ae ← reflectCTerm a
return mkAppN (mkConst ``CTerm.glueIn) #[φE, te, ae]
| .unglue φ f g => do
let φE ← reflectFaceFormula φ
let fe ← reflectCTerm f
let ge ← reflectCTerm g
return mkAppN (mkConst ``CTerm.unglue) #[φE, fe, ge]
| .pair a b => do
let ae ← reflectCTerm a
let be ← reflectCTerm b
return mkAppN (mkConst ``CTerm.pair) #[ae, be]
| .fst t => do
let te ← reflectCTerm t
return mkApp (mkConst ``CTerm.fst) te
| .snd t => do
let te ← reflectCTerm t
return mkApp (mkConst ``CTerm.snd) te
| .dimExpr r => do
let re ← reflectDimExpr r
return mkApp (mkConst ``CTerm.dimExpr) re
| .ctor S c params args => do
let SE ← reflectCTypeSchema S
let cE := mkStrLit c
let paramsE ← reflectCTypeAnyList params
let argsE ← reflectCTermList args
return mkAppN (mkConst ``CTerm.ctor) #[SE, cE, paramsE, argsE]
| .indElim S params motive branches target => do
let SE ← reflectCTypeSchema S
let paramsE ← reflectCTypeAnyList params
let motiveE ← reflectCTerm motive
let branchesE ← reflectBranchesList branches
let targetE ← reflectCTerm target
return mkAppN (mkConst ``CTerm.indElim)
#[SE, paramsE, motiveE, branchesE, targetE]
| @CTerm.code A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CTerm.code) #[E, AE]
| .flatIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.flatIntro) ae
| .sharpIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.sharpIntro) ae
| .shapeIntro a => do
let ae ← reflectCTerm a
return mkApp (mkConst ``CTerm.shapeIntro) ae
| .flatElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.flatElim) #[fe, me]
| .sharpElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.sharpElim) #[fe, me]
| .shapeElim f m => do
let fe ← reflectCTerm f
let me ← reflectCTerm m
return mkAppN (mkConst ``CTerm.shapeElim) #[fe, me]
/-- Reflect a `List (Σ : ULevel, CType )`. The Σ pairs are
built via `mkSigmaULevelCType`; the list is `List.cons`-spine. -/
partial def reflectCTypeAnyList :
List (Σ : ULevel, CType ) → MetaM Expr
| [] =>
return mkApp (mkConst ``List.nil [Level.zero]) cTypeSigmaExpr
| ⟨ℓ, A⟩ :: rest => do
let E ← reflectULevel
let AE ← reflectCType A
let pairE := mkSigmaULevelCType E AE
let restE ← reflectCTypeAnyList rest
return mkAppN (mkConst ``List.cons [Level.zero])
#[cTypeSigmaExpr, pairE, restE]
/-- Reflect a `List CTerm`. -/
partial def reflectCTermList : List CTerm → MetaM Expr
| [] =>
return mkApp (mkConst ``List.nil [Level.zero]) (mkConst ``CTerm)
| t :: rest => do
let te ← reflectCTerm t
let restE ← reflectCTermList rest
return mkAppN (mkConst ``List.cons [Level.zero])
#[mkConst ``CTerm, te, restE]
/-- Reflect a `List (FaceFormula × CTerm)` — the partial-element
clauses of a multi-clause composition. -/
partial def reflectClausesList :
List (FaceFormula × CTerm) → MetaM Expr
| [] =>
let pairTy := mkAppN (mkConst ``Prod [Level.zero, Level.zero])
#[mkConst ``FaceFormula, mkConst ``CTerm]
return mkApp (mkConst ``List.nil [Level.zero]) pairTy
| (φ, t) :: rest => do
let φE ← reflectFaceFormula φ
let te ← reflectCTerm t
let pairE := mkAppN (mkConst ``Prod.mk [Level.zero, Level.zero])
#[mkConst ``FaceFormula, mkConst ``CTerm, φE, te]
let restE ← reflectClausesList rest
let pairTy := mkAppN (mkConst ``Prod [Level.zero, Level.zero])
#[mkConst ``FaceFormula, mkConst ``CTerm]
return mkAppN (mkConst ``List.cons [Level.zero])
#[pairTy, pairE, restE]
/-- Reflect a `List (String × CTerm)` — the named branches of an
`indElim`. -/
partial def reflectBranchesList :
List (String × CTerm) → MetaM Expr
| [] =>
let pairTy := mkAppN (mkConst ``Prod [Level.zero, Level.zero])
#[mkConst ``String, mkConst ``CTerm]
return mkApp (mkConst ``List.nil [Level.zero]) pairTy
| (n, b) :: rest => do
let bE ← reflectCTerm b
let pairE := mkAppN (mkConst ``Prod.mk [Level.zero, Level.zero])
#[mkConst ``String, mkConst ``CTerm, mkStrLit n, bE]
let restE ← reflectBranchesList rest
let pairTy := mkAppN (mkConst ``Prod [Level.zero, Level.zero])
#[mkConst ``String, mkConst ``CTerm]
return mkAppN (mkConst ``List.cons [Level.zero])
#[pairTy, pairE, restE]
/-- Reflect a `CTypeSchema` (the `mk name numParams ctors` form). -/
partial def reflectCTypeSchema : CTypeSchema → MetaM Expr := fun S => do
match S with
| .mk name nP ctors =>
let nameE := mkStrLit name
let nPE := mkNatLit nP
let ctorsE ← reflectCtorSpecList ctors
return mkAppN (mkConst ``CTypeSchema.mk) #[nameE, nPE, ctorsE]
/-- Reflect a `List CtorSpec`. -/
partial def reflectCtorSpecList : List CtorSpec → MetaM Expr
| [] =>
return mkApp (mkConst ``List.nil [Level.zero]) (mkConst ``CtorSpec)
| c :: rest => do
let cE ← reflectCtorSpec c
let restE ← reflectCtorSpecList rest
return mkAppN (mkConst ``List.cons [Level.zero])
#[mkConst ``CtorSpec, cE, restE]
/-- Reflect a `CtorSpec` (the `mk name args boundary` form). -/
partial def reflectCtorSpec : CtorSpec → MetaM Expr := fun cs => do
match cs with
| .mk name args bdy =>
let nameE := mkStrLit name
let argsE ← reflectCTypeArgList args
let bdyE ← reflectClausesList bdy
return mkAppN (mkConst ``CtorSpec.mk) #[nameE, argsE, bdyE]
/-- Reflect a `List CTypeArg`. -/
partial def reflectCTypeArgList : List CTypeArg → MetaM Expr
| [] =>
return mkApp (mkConst ``List.nil [Level.zero]) (mkConst ``CTypeArg)
| a :: rest => do
let aE ← reflectCTypeArg a
let restE ← reflectCTypeArgList rest
return mkAppN (mkConst ``List.cons [Level.zero])
#[mkConst ``CTypeArg, aE, restE]
/-- Reflect a `CTypeArg` — every constructor: `.type A`, `.param i`,
`.self`, `.dim`. -/
partial def reflectCTypeArg : CTypeArg → MetaM Expr
| @CTypeArg.type A => do
let E ← reflectULevel
let AE ← reflectCType A
return mkAppN (mkConst ``CTypeArg.type) #[E, AE]
| .param i =>
return mkApp (mkConst ``CTypeArg.param) (mkNatLit i)
| .self =>
return mkConst ``CTypeArg.self
| .dim =>
return mkConst ``CTypeArg.dim
end
-- ── §4. Reification: Expr → ULevel / CType / CTerm ────────────────────────
/-- Reify a `Lean.Expr` back to a `ULevel`. Returns `none` if the
Expr does not match the shape `@ULevel.zero` or `@ULevel.succ <e>`.
Pattern: walk down `Expr.app`-chains; at each leaf, check the head
constant name against `ULevel.zero` / `ULevel.succ`. This is the
strict structural inverse of `reflectULevel`. -/
partial def reifyULevel : Expr → MetaM (Option ULevel) := fun e => do
-- Reduce metadata wrappers and beta-redexes that may be sitting
-- around the literal constructor application.
let e ← whnf e
match e.getAppFnArgs with
| (``ULevel.zero, _) => return some .zero
| (``ULevel.succ, args) =>
if h : args.size = 1 then
match ← reifyULevel (args[0]'(by omega)) with
| some n => return some (.succ n)
| none => return none
else
return none
| _ => return none
/-- Reify the literal-Nat encoding produced by `mkNatLit n`. After
`whnf`, an `OfNat.ofNat`-shaped numeral reduces to its raw form
via `Expr.nat?`. -/
partial def reifyNatLit (e : Expr) : MetaM (Option Nat) := do
let e ← whnf e
match e.nat? with
| some n => return some n
| none =>
-- Also accept the raw literal form `.lit (.natVal n)` directly
-- (in case `whnf` has already normalised through `OfNat.ofNat`).
match e with
| .lit (.natVal n) => return some n
| _ => return none
/-- Reify a `mkStrLit s`-encoded expression back to its String. -/
partial def reifyStrLit (e : Expr) : MetaM (Option String) := do
let e ← whnf e
match e with
| .lit (.strVal s) => return some s
| _ => return none
mutual
/-- Reify a `Lean.Expr` back to a `DimVar`. Inverts `reflectDimVar`:
a single-field structure carrying `name : String`. -/
partial def reifyDimVar : Expr → MetaM (Option DimVar) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``DimVar.mk, args) =>
-- single field: the dim variable's name string
if h : args.size = 1 then
match ← reifyStrLit (args[0]'(by omega)) with
| some name => return some ⟨name⟩
| none => return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `DimExpr`. Inverts `reflectDimExpr`:
one explicit arm per de-Morgan-algebra constructor. -/
partial def reifyDimExpr : Expr → MetaM (Option DimExpr) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``DimExpr.zero, _) => return some .zero
| (``DimExpr.one, _) => return some .one
| (``DimExpr.var, args) =>
-- one DimVar payload
if h : args.size = 1 then
match ← reifyDimVar (args[0]'(by omega)) with
| some i => return some (.var i)
| none => return none
else
return none
| (``DimExpr.inv, args) =>
-- one DimExpr payload
if h : args.size = 1 then
match ← reifyDimExpr (args[0]'(by omega)) with
| some r => return some (.inv r)
| none => return none
else
return none
| (``DimExpr.meet, args) =>
-- two DimExpr payloads
if h : args.size = 2 then
match ← reifyDimExpr (args[0]'(by omega)) with
| none => return none
| some r =>
match ← reifyDimExpr (args[1]'(by omega)) with
| none => return none
| some s => return some (.meet r s)
else
return none
| (``DimExpr.join, args) =>
-- two DimExpr payloads
if h : args.size = 2 then
match ← reifyDimExpr (args[0]'(by omega)) with
| none => return none
| some r =>
match ← reifyDimExpr (args[1]'(by omega)) with
| none => return none
| some s => return some (.join r s)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `FaceFormula`. Inverts
`reflectFaceFormula`: one explicit arm per constructor. -/
partial def reifyFaceFormula : Expr → MetaM (Option FaceFormula) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``FaceFormula.bot, _) => return some .bot
| (``FaceFormula.top, _) => return some .top
| (``FaceFormula.eq0, args) =>
-- one DimVar payload (the dimension variable being constrained)
if h : args.size = 1 then
match ← reifyDimVar (args[0]'(by omega)) with
| some i => return some (.eq0 i)
| none => return none
else
return none
| (``FaceFormula.eq1, args) =>
-- one DimVar payload
if h : args.size = 1 then
match ← reifyDimVar (args[0]'(by omega)) with
| some i => return some (.eq1 i)
| none => return none
else
return none
| (``FaceFormula.meet, args) =>
-- two FaceFormula payloads
if h : args.size = 2 then
match ← reifyFaceFormula (args[0]'(by omega)) with
| none => return none
| some a =>
match ← reifyFaceFormula (args[1]'(by omega)) with
| none => return none
| some b => return some (.meet a b)
else
return none
| (``FaceFormula.join, args) =>
-- two FaceFormula payloads
if h : args.size = 2 then
match ← reifyFaceFormula (args[0]'(by omega)) with
| none => return none
| some a =>
match ← reifyFaceFormula (args[1]'(by omega)) with
| none => return none
| some b => return some (.join a b)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `Σ : ULevel, CType `. Inverts
`reflectCType` arm-for-arm: nine constructors plus a final
catch-all for unrecognised shapes. -/
partial def reifyCType :
Expr → MetaM (Option (Σ : ULevel, CType )) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``CType.univ, args) =>
-- args = [_innerE]; result level = .succ _inner
if h : args.size = 1 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some _inner => return some ⟨ULevel.succ _inner, .univ⟩
else
return none
| (``CType.pi, args) =>
-- args = [_aE, _bE, varE, AE, BE]; result level = max _a _b
if h : args.size = 5 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some _a =>
match ← reifyULevel (args[1]'(by omega)) with
| none => return none
| some _b =>
match ← reifyStrLit (args[2]'(by omega)) with
| none => return none
| some var =>
match ← reifyCType (args[3]'(by omega)) with
| none => return none
| some ⟨_a_rec, A⟩ =>
if hA : _a_rec = _a then
match ← reifyCType (args[4]'(by omega)) with
| none => return none
| some ⟨_b_rec, B⟩ =>
if hB : _b_rec = _b then
let A' : CType _a := hA ▸ A
let B' : CType _b := hB ▸ B
return some ⟨ULevel.max _a _b, .pi var A' B'⟩
else
return none
else
return none
else
return none
| (``CType.sigma, args) =>
-- args = [_aE, _bE, varE, AE, BE]; same shape as pi
if h : args.size = 5 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some _a =>
match ← reifyULevel (args[1]'(by omega)) with
| none => return none
| some _b =>
match ← reifyStrLit (args[2]'(by omega)) with
| none => return none
| some var =>
match ← reifyCType (args[3]'(by omega)) with
| none => return none
| some ⟨_a_rec, A⟩ =>
if hA : _a_rec = _a then
match ← reifyCType (args[4]'(by omega)) with
| none => return none
| some ⟨_b_rec, B⟩ =>
if hB : _b_rec = _b then
let A' : CType _a := hA ▸ A
let B' : CType _b := hB ▸ B
return some ⟨ULevel.max _a _b, .sigma var A' B'⟩
else
return none
else
return none
else
return none
| (``CType.path, args) =>
-- args = [E, AE, aE, bE]; result level =
if h : args.size = 4 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
match ← reifyCTerm (args[2]'(by omega)) with
| none => return none
| some a =>
match ← reifyCTerm (args[3]'(by omega)) with
| none => return none
| some b =>
let A' : CType := hA ▸ A
return some ⟨ℓ, .path A' a b⟩
else
return none
else
return none
| (``CType.glue, args) =>
-- args = [E, φE, TE, fE, fInvE, secE, retE, cohE, AE]; level =
if h : args.size = 9 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyFaceFormula (args[1]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCType (args[2]'(by omega)) with
| none => return none
| some ⟨_T_rec, T⟩ =>
if hT : _T_rec = then
match ← reifyCTerm (args[3]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[4]'(by omega)) with
| none => return none
| some fInv =>
match ← reifyCTerm (args[5]'(by omega)) with
| none => return none
| some sec =>
match ← reifyCTerm (args[6]'(by omega)) with
| none => return none
| some ret =>
match ← reifyCTerm (args[7]'(by omega)) with
| none => return none
| some coh =>
match ← reifyCType (args[8]'(by omega)) with
| none => return none
| some ⟨_A_rec, A⟩ =>
if hA : _A_rec = then
let T' : CType := hT ▸ T
let A' : CType := hA ▸ A
return some ⟨ℓ, .glue φ T' f fInv sec ret coh A'⟩
else
return none
else
return none
else
return none
| (``CType.ind, args) =>
-- args = [E, SE, paramsE]; result level = (user-specified)
if h : args.size = 3 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCTypeSchema (args[1]'(by omega)) with
| none => return none
| some S =>
match ← reifyCTypeAnyList (args[2]'(by omega)) with
| none => return none
| some params => return some ⟨ℓ, .ind ( := ) S params⟩
else
return none
| (``CType.interval, _) =>
-- nullary; result level = .zero
return some ⟨ULevel.zero, .interval⟩
| (``CType.lift, args) =>
-- args = [_innerE, AE]; result level = .succ _inner
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some _inner =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = _inner then
let A' : CType _inner := hA ▸ A
return some ⟨ULevel.succ _inner, .lift A'⟩
else
return none
else
return none
| (``CType.El, args) =>
-- args = [E, PE]; result level =
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some P => return some ⟨ℓ, .El ( := ) P⟩
else
return none
| (``CType.flat, args) =>
-- args = [E, AE]; result level = (level-preserving modality)
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .flat A'⟩
else
return none
else
return none
| (``CType.sharp, args) =>
-- args = [E, AE]; result level =
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .sharp A'⟩
else
return none
else
return none
| (``CType.shape, args) =>
-- args = [E, AE]; result level =
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some ⟨ℓ, .shape A'⟩
else
return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `CTerm`. Inverts `reflectCTerm`
arm-for-arm: seventeen constructors plus a final catch-all. -/
partial def reifyCTerm : Expr → MetaM (Option CTerm) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``CTerm.var, args) =>
-- args = [mkStrLit x]
if h : args.size = 1 then
match ← reifyStrLit (args[0]'(by omega)) with
| some x => return some (.var x)
| none => return none
else
return none
| (``CTerm.lam, args) =>
-- args = [mkStrLit x, te]
if h : args.size = 2 then
match ← reifyStrLit (args[0]'(by omega)) with
| none => return none
| some x =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some t => return some (.lam x t)
else
return none
| (``CTerm.app, args) =>
-- args = [fe, ae]
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some a => return some (.app f a)
else
return none
| (``CTerm.plam, args) =>
-- args = [ie, te]
if h : args.size = 2 then
match ← reifyDimVar (args[0]'(by omega)) with
| none => return none
| some i =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some t => return some (.plam i t)
else
return none
| (``CTerm.papp, args) =>
-- args = [te, re]
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some t =>
match ← reifyDimExpr (args[1]'(by omega)) with
| none => return none
| some r => return some (.papp t r)
else
return none
| (``CTerm.transp, args) =>
-- args = [ie, E, AE, φE, te]
if h : args.size = 5 then
match ← reifyDimVar (args[0]'(by omega)) with
| none => return none
| some i =>
match ← reifyULevel (args[1]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[2]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
match ← reifyFaceFormula (args[3]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCTerm (args[4]'(by omega)) with
| none => return none
| some t =>
let A' : CType := hA ▸ A
return some (.transp i ( := ) A' φ t)
else
return none
else
return none
| (``CTerm.comp, args) =>
-- args = [ie, E, AE, φE, ue, te]
if h : args.size = 6 then
match ← reifyDimVar (args[0]'(by omega)) with
| none => return none
| some i =>
match ← reifyULevel (args[1]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[2]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
match ← reifyFaceFormula (args[3]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCTerm (args[4]'(by omega)) with
| none => return none
| some u =>
match ← reifyCTerm (args[5]'(by omega)) with
| none => return none
| some t =>
let A' : CType := hA ▸ A
return some (.comp i ( := ) A' φ u t)
else
return none
else
return none
| (``CTerm.compN, args) =>
-- args = [ie, E, AE, clausesE, te]
if h : args.size = 5 then
match ← reifyDimVar (args[0]'(by omega)) with
| none => return none
| some i =>
match ← reifyULevel (args[1]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[2]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
match ← reifyClausesList (args[3]'(by omega)) with
| none => return none
| some clauses =>
match ← reifyCTerm (args[4]'(by omega)) with
| none => return none
| some t =>
let A' : CType := hA ▸ A
return some (.compN i ( := ) A' clauses t)
else
return none
else
return none
| (``CTerm.glueIn, args) =>
-- args = [φE, te, ae]
if h : args.size = 3 then
match ← reifyFaceFormula (args[0]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some t =>
match ← reifyCTerm (args[2]'(by omega)) with
| none => return none
| some a => return some (.glueIn φ t a)
else
return none
| (``CTerm.unglue, args) =>
-- args = [φE, fe, ge]
if h : args.size = 3 then
match ← reifyFaceFormula (args[0]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[2]'(by omega)) with
| none => return none
| some g => return some (.unglue φ f g)
else
return none
| (``CTerm.pair, args) =>
-- args = [ae, be]
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some b => return some (.pair a b)
else
return none
| (``CTerm.fst, args) =>
-- args = [te]
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some t => return some (.fst t)
else
return none
| (``CTerm.snd, args) =>
-- args = [te]
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some t => return some (.snd t)
else
return none
| (``CTerm.dimExpr, args) =>
-- args = [re]
if h : args.size = 1 then
match ← reifyDimExpr (args[0]'(by omega)) with
| none => return none
| some r => return some (.dimExpr r)
else
return none
| (``CTerm.ctor, args) =>
-- args = [SE, cE, paramsE, argsE]
if h : args.size = 4 then
match ← reifyCTypeSchema (args[0]'(by omega)) with
| none => return none
| some S =>
match ← reifyStrLit (args[1]'(by omega)) with
| none => return none
| some c =>
match ← reifyCTypeAnyList (args[2]'(by omega)) with
| none => return none
| some params =>
match ← reifyCTermList (args[3]'(by omega)) with
| none => return none
| some args' => return some (.ctor S c params args')
else
return none
| (``CTerm.indElim, args) =>
-- args = [SE, paramsE, motiveE, branchesE, targetE]
if h : args.size = 5 then
match ← reifyCTypeSchema (args[0]'(by omega)) with
| none => return none
| some S =>
match ← reifyCTypeAnyList (args[1]'(by omega)) with
| none => return none
| some params =>
match ← reifyCTerm (args[2]'(by omega)) with
| none => return none
| some motive =>
match ← reifyBranchesList (args[3]'(by omega)) with
| none => return none
| some branches =>
match ← reifyCTerm (args[4]'(by omega)) with
| none => return none
| some target =>
return some (.indElim S params motive branches target)
else
return none
| (``CTerm.code, args) =>
-- args = [E, AE]
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some (.code ( := ) A')
else
return none
else
return none
| (``CTerm.flatIntro, args) =>
-- args = [ae]
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.flatIntro a)
else
return none
| (``CTerm.sharpIntro, args) =>
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.sharpIntro a)
else
return none
| (``CTerm.shapeIntro, args) =>
if h : args.size = 1 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some a => return some (.shapeIntro a)
else
return none
| (``CTerm.flatElim, args) =>
-- args = [fe, me]
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.flatElim f m)
else
return none
| (``CTerm.sharpElim, args) =>
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.sharpElim f m)
else
return none
| (``CTerm.shapeElim, args) =>
if h : args.size = 2 then
match ← reifyCTerm (args[0]'(by omega)) with
| none => return none
| some f =>
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some m => return some (.shapeElim f m)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List (Σ : ULevel, CType )`.
Inverts `reflectCTypeAnyList`: List.nil/cons spine over Sigma pairs. -/
partial def reifyCTypeAnyList :
Expr → MetaM (Option (List (Σ : ULevel, CType ))) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty list; element-type arg ignored (encoded by reflect side)
return some []
| (``List.cons, args) =>
-- args = [elemTy, headPair, tail]
if h : args.size = 3 then
-- head is `Sigma.mk _ _ E AE`; decode it directly
let headE ← whnf (args[1]'(by omega))
match headE.getAppFnArgs with
| (``Sigma.mk, sargs) =>
-- sargs = [ULevel, family, E, AE]
if hs : sargs.size = 4 then
match ← reifyULevel (sargs[2]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (sargs[3]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
match ← reifyCTypeAnyList (args[2]'(by omega)) with
| none => return none
| some rest => return some (⟨ℓ, A'⟩ :: rest)
else
return none
else
return none
| _ => return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List CTerm`. Inverts
`reflectCTermList`: List.nil/cons spine over CTerm elements. -/
partial def reifyCTermList :
Expr → MetaM (Option (List CTerm)) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty list
return some []
| (``List.cons, args) =>
-- args = [elemTy, headTerm, tail]
if h : args.size = 3 then
match ← reifyCTerm (args[1]'(by omega)) with
| none => return none
| some t =>
match ← reifyCTermList (args[2]'(by omega)) with
| none => return none
| some rest => return some (t :: rest)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List (FaceFormula × CTerm)`.
Inverts `reflectClausesList`: List.nil/cons spine over Prod pairs. -/
partial def reifyClausesList :
Expr → MetaM (Option (List (FaceFormula × CTerm))) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty clause list
return some []
| (``List.cons, args) =>
-- args = [elemTy, headPair, tail]
if h : args.size = 3 then
let headE ← whnf (args[1]'(by omega))
match headE.getAppFnArgs with
| (``Prod.mk, pargs) =>
-- pargs = [αTy, βTy, φE, tE]
if hp : pargs.size = 4 then
match ← reifyFaceFormula (pargs[2]'(by omega)) with
| none => return none
| some φ =>
match ← reifyCTerm (pargs[3]'(by omega)) with
| none => return none
| some t =>
match ← reifyClausesList (args[2]'(by omega)) with
| none => return none
| some rest => return some ((φ, t) :: rest)
else
return none
| _ => return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List (String × CTerm)`. Inverts
`reflectBranchesList`: List.nil/cons spine over Prod pairs. -/
partial def reifyBranchesList :
Expr → MetaM (Option (List (String × CTerm))) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty branch list
return some []
| (``List.cons, args) =>
-- args = [elemTy, headPair, tail]
if h : args.size = 3 then
let headE ← whnf (args[1]'(by omega))
match headE.getAppFnArgs with
| (``Prod.mk, pargs) =>
-- pargs = [αTy, βTy, nameE, bodyE]
if hp : pargs.size = 4 then
match ← reifyStrLit (pargs[2]'(by omega)) with
| none => return none
| some n =>
match ← reifyCTerm (pargs[3]'(by omega)) with
| none => return none
| some b =>
match ← reifyBranchesList (args[2]'(by omega)) with
| none => return none
| some rest => return some ((n, b) :: rest)
else
return none
| _ => return none
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `CTypeSchema`. Inverts
`reflectCTypeSchema`: the `mk name numParams ctors` form. -/
partial def reifyCTypeSchema : Expr → MetaM (Option CTypeSchema) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``CTypeSchema.mk, args) =>
-- args = [nameE, nPE, ctorsE]
if h : args.size = 3 then
match ← reifyStrLit (args[0]'(by omega)) with
| none => return none
| some name =>
match ← reifyNatLit (args[1]'(by omega)) with
| none => return none
| some nP =>
match ← reifyCtorSpecList (args[2]'(by omega)) with
| none => return none
| some ctors => return some (.mk name nP ctors)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List CtorSpec`. Inverts
`reflectCtorSpecList`: List.nil/cons spine over CtorSpecs. -/
partial def reifyCtorSpecList :
Expr → MetaM (Option (List CtorSpec)) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty CtorSpec list
return some []
| (``List.cons, args) =>
-- args = [elemTy, head, tail]
if h : args.size = 3 then
match ← reifyCtorSpec (args[1]'(by omega)) with
| none => return none
| some c =>
match ← reifyCtorSpecList (args[2]'(by omega)) with
| none => return none
| some rest => return some (c :: rest)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `CtorSpec`. Inverts
`reflectCtorSpec`: the `mk name args boundary` form. -/
partial def reifyCtorSpec : Expr → MetaM (Option CtorSpec) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``CtorSpec.mk, args) =>
-- args = [nameE, argsE, bdyE]
if h : args.size = 3 then
match ← reifyStrLit (args[0]'(by omega)) with
| none => return none
| some name =>
match ← reifyCTypeArgList (args[1]'(by omega)) with
| none => return none
| some args' =>
match ← reifyClausesList (args[2]'(by omega)) with
| none => return none
| some bdy => return some (.mk name args' bdy)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `List CTypeArg`. Inverts
`reflectCTypeArgList`: List.nil/cons spine over CTypeArgs. -/
partial def reifyCTypeArgList :
Expr → MetaM (Option (List CTypeArg)) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``List.nil, _) =>
-- empty CTypeArg list
return some []
| (``List.cons, args) =>
-- args = [elemTy, head, tail]
if h : args.size = 3 then
match ← reifyCTypeArg (args[1]'(by omega)) with
| none => return none
| some a =>
match ← reifyCTypeArgList (args[2]'(by omega)) with
| none => return none
| some rest => return some (a :: rest)
else
return none
| _ => return none
/-- Reify a `Lean.Expr` back to a `CTypeArg`. Inverts
`reflectCTypeArg`: four constructors (.type, .param, .self, .dim). -/
partial def reifyCTypeArg : Expr → MetaM (Option CTypeArg) := fun e => do
let e ← whnf e
match e.getAppFnArgs with
| (``CTypeArg.type, args) =>
-- args = [E, AE]; needs Sigma-style level coherence check
if h : args.size = 2 then
match ← reifyULevel (args[0]'(by omega)) with
| none => return none
| some =>
match ← reifyCType (args[1]'(by omega)) with
| none => return none
| some ⟨_rec, A⟩ =>
if hA : _rec = then
let A' : CType := hA ▸ A
return some (.type ( := ) A')
else
return none
else
return none
| (``CTypeArg.param, args) =>
-- args = [iE]
if h : args.size = 1 then
match ← reifyNatLit (args[0]'(by omega)) with
| none => return none
| some i => return some (.param i)
else
return none
| (``CTypeArg.self, _) => return some .self
| (``CTypeArg.dim, _) => return some .dim
| _ => return none
end
-- ── §5. Contract registry ──────────────────────────────────────────────────
/-- Type-erased Contract package — bundles a Contract with its
universe level so the registry can hold heterogeneous-level
entries homogeneously. -/
structure ContractEntry where
/-- The universe level the contract operates at. -/
level : ULevel
/-- The contract itself: a function from CType to CTerm. -/
contract : Contract level
/-- The contract registry: maps `Lean.Name` to `ContractEntry`.
Initialised empty. Contracts register themselves in their
defining module's `initialize` block via `Contract.register`;
tactics and other consumers look them up by name. -/
initialize contractRegistry : IO.Ref (Std.HashMap Lean.Name ContractEntry) ←
IO.mkRef ∅
/-- Register a Contract under the given `Lean.Name`. Subsequent
lookups via `Contract.lookupByName n` return the newly registered
entry. Re-registering the same name overwrites the previous
entry (last-write-wins). -/
def Contract.register (n : Lean.Name) (e : ContractEntry) : IO Unit := do
contractRegistry.modify (·.insert n e)
/-- Look up a Contract by name. Returns `none` if no entry has been
registered under `n`. -/
def Contract.lookupByName (n : Lean.Name) : IO (Option ContractEntry) := do
let registry ← contractRegistry.get
return registry[n]?
/-- List all registered Contract names (in arbitrary HashMap order). -/
def Contract.allRegistered : IO (List Lean.Name) := do
let registry ← contractRegistry.get
return registry.toList.map (·.1)
-- ── §6. Round-trip theorems ────────────────────────────────────────────────
/-- Round-trip property: reflecting then reifying a CTerm in a single
`MetaM` computation yields `pure (some t)`.
Stated as an equation between two `MetaM (Option CTerm)`
computations: the `reflectCTerm` followed by `reifyCTerm` chain
must produce the original CTerm wrapped in `some`.
Proof outline (structural induction on `t`):
· Each CTerm constructor's reflect-arm produces an Expr whose
`getAppFnArgs` yields the constructor's name and reflected
sub-payloads.
· Each CTerm constructor's reify-arm (once written, currently
sorry'd above) inverts the reflect-arm exactly: reading off
`getAppFnArgs` recovers the constructor's name; recursive
`reifyCType` / `reifyCTerm` / `reifyDimVar` / `reifyDimExpr` /
`reifyFaceFormula` calls invert the sub-payload reflections
by induction.
· The literal-encoding round-trips (`mkStrLit s` ↔ extract
`Expr.litValue? = some (.strVal s)`; `mkNatLit n` ↔ extract
`Expr.natLitValue?`) close at the leaves.
The proof is currently sorry'd pending the meta-level
`Expr`-equality framework that gives reduction-up-to-elaboration
semantics for `MetaM`-bound equations. -/
theorem reflectCTerm_reifyCTerm_roundtrip (t : CTerm) :
(do let e ← reflectCTerm t; reifyCTerm e) = (pure (some t) : MetaM (Option CTerm)) := by
-- waits on: meta-level reflection-roundtrip framework
-- (Expr-equality up to elaboration in a fixed Environment).
-- Once the framework lands, this discharges by structural
-- induction on `t`, with each constructor's case closed by
-- `simp [reflectCTerm, reifyCTerm, mkApp, mkAppN, ...]` and
-- the corresponding arm of the (yet-to-be-completed)
-- reifyCTerm body.
sorry
/-- Round-trip property: reflecting then reifying a CType in a single
`MetaM` computation yields `pure (some ⟨ℓ, T⟩)`. Same shape and
proof outline as the CTerm round-trip. -/
theorem reflectCType_reifyCType_roundtrip
{ : ULevel} (T : CType ) :
(do let e ← reflectCType T; reifyCType e) =
(pure (some ⟨ℓ, T⟩) : MetaM (Option (Σ : ULevel, CType ))) := by
-- waits on: meta-level reflection-roundtrip framework, as above.
sorry
/-- Round-trip property: reflecting then reifying a `ULevel` in a
single `MetaM` computation yields `pure (some )`. This is the
only round-trip whose proof obligation is fully elaborable
structurally — it does not depend on the larger `Expr`-elaboration
framework. Stated here for symmetry with the CType / CTerm
round-trips. -/
theorem reflectULevel_reifyULevel_roundtrip ( : ULevel) :
(do let e ← reflectULevel ; reifyULevel e) =
(pure (some ) : MetaM (Option ULevel)) := by
-- waits on: meta-level reflection-roundtrip framework
-- (Expr-equality up to elaboration in a fixed Environment),
-- even though the structural recursion on `` is two-arm
-- and small, the `whnf` step in `reifyULevel` operates in
-- the elaborator monad and its image equation requires the
-- same framework as the CType / CTerm round-trips.
sorry
/-- Reflection preserves the CType-typing relationship: if the CTerm
`t` has CType `T` in the empty context (according to the engine's
`HasType` judgment), then there exist Lean Exprs `et` and `eT`
that are the reflections of `t` and `T` respectively, and they
stand in a corresponding meta-level typing relationship under
elaboration (i.e., `et : eT` once the Exprs are elaborated in a
context with the engine's namespace open).
The Lean-side typing-correspondence statement is:
HasType [] t T →
∃ (eT et : Expr),
(do let e1 ← reflectCType T
let e2 ← reflectCTerm t
pure (e1, e2)) = (pure (eT, et) : MetaM (Expr × Expr))
The substantive content (that `et : eT` after elaboration) lives
in the `MetaM`-equation: the reflected pair, evaluated in the
elaborator, must agree with the original `(T, t)` pair under the
encoding.
Proof depends on the same meta-level `Expr`-elaboration framework
that the round-trip theorems wait on. -/
theorem reflect_preserves_typing
{ : ULevel} (t : CTerm) (T : CType )
(_h : HasType [] t T) :
∃ (eT et : Expr),
(do
let e1 ← reflectCType T
let e2 ← reflectCTerm t
pure (e1, e2)) = (pure (eT, et) : MetaM (Expr × Expr)) := by
-- waits on: a meta-level Expr-typing framework that reads the
-- elaborated types of `reflectCTerm t` and
-- `reflectCType T` and compares them. The current
-- statement asserts only the existence of the reflected
-- pair and an equation tying it to the literal pair; the
-- full `et : eT` correspondence requires the elaborator
-- framework to be available at the meta level.
sorry
end CubicalTransport.Reflect