Imports
/-
Copyright (c) 2026 Terence Rokop. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Terence Rokop
-/
module
public import Geb.Mathlib.Data.PFunctor.IndRec.Slice
public import Geb.Mathlib.Data.PFunctor.Slice.WThe data type and decoder described by an IR code
An endo-code γ : IR I I denotes an endofunctor of Type/I, and the data
type it describes is that endofunctor's initial algebra, carrying its
decoder as the algebra's structure map into I — the µ γ and
decode γ of [HancockMcBrideGhaniMalatestaAltenkirch2013], Section 3.
It is obtained here from the translation IR.toSlicePFunctor of the code
to a slice polynomial functor (Geb/Mathlib/Data/PFunctor/IndRec/Slice.lean)
and the W-type of that functor (Geb/Mathlib/Data/PFunctor/Slice/W.lean).
Routing through the translation is what makes the fixed point available at
all: IR.interpObj computes by recursion on the code, so a data type
defined directly as the fixed point of IR.interpObj γ would be rejected
for the code variable γ, whereas SlicePFunctor.W is a subtype of an
ordinary WType.
The algebra structure map — the constructor IR.W.mk, the in of
Section 3 — needs a node of the direct interpretation to be presented as a
node of the translated polynomial. That presentation is one direction of
the agreement of the two semantics established by Lemma 2 of
[HancockMcBrideGhaniMalatestaAltenkirch2013]. Its type mentions both
semantics, so on its own it has no carrier to be folded into; it is
computed instead as the third component of IR.posSlice, a fold whose
other two components are the interpretation and the slice polynomial
functor themselves.
Main definitions
IR.PosToSliceSig — the signature of the presentation of a node of an
interpretation as a node of a slice polynomial functor.
IR.posToSliceIota, IR.posToSliceSigma, IR.posToSliceDelta — the
per-shape steps of that presentation.
IR.PosSlice, IR.posSliceIota, IR.posSliceSigma,
IR.posSliceDelta, IR.posSliceAlg, IR.posSlice — the three
components folded together, the per-shape cases, the algebra assembling
them, and the fold.
IR.W, IR.wDecode — the data type an endo-code describes and its
decoder (µ γ and decode γ), with IR.wObj the object of Type/I
they form.
IR.W.mk — the constructor, the in of Section 3.
Main statements
IR.posSlice_interp, IR.posSlice_spf — the first two components of
IR.posSlice are IR.interpObj and IR.toSlicePFunctor.
IR.wDecode_mk — the decoder of a constructed element is the
interpretation's decoding of the node it was constructed from: the
algebra law of IR.W.mk.
Implementation notes
IR.W is stated for codes at IR.{max uA uI, uB, uI, uI}. The index
universe must not exceed the code's arity universes: the objects of
Type/I that IR.interpObj accepts have their carriers at
Type (max uA uB), while the carrier of the W-type is at
Type (max uA uB uI), so the two agree exactly when uI ≤ max uA uB.
IR.posSlice is a fold by IR.elim, whose computation rule is
definitional, and not by the recursor IR.rec, whose computation rule is
not. The difference is what lets everything built on it reduce on a
closed code, so that a value equation about a concrete data type is
rfl. It is bought by defining IR.W and IR.W.mk in terms of the
fold's components rather than of IR.interpObj and IR.toSlicePFunctor,
which IR.posSlice_interp and IR.posSlice_spf identify them with.
References
[HancockMcBrideGhaniMalatestaAltenkirch2013]
Tags
inductive-recursive, initial algebra, W-type, polynomial functor, slice category
@[expose] public sectionuniverse uA uB uI uOnamespace IndRecopen CategoryTheorynamespace IRvariable (I : Type uI) (O : Type uO)
The signature of the presentation of a node of an interpretation α
as a node of a slice polynomial functor F, at the same output index: a
node of α at an object X of Type/I yields a node of F at X whose
shape-output index is the node's decoding.
set_option linter.checkUnivs false indef PosToSliceSig (α : FreeCoprodCompDisc.Map.{max uA uB, uI, uO} I O)
(F : SlicePFunctor.{max uA uB uI, uB, uI, uO} I O) :
Type (max (uA + 1) (uB + 1) uI) :=
(X : FreeCoprodCompDisc.{max uA uB, uI} I) → (z : (α X).1) →
{ y : F.toSliceDomPFunctor.Obj X.2 // F.q y.1.1 = (α X).2 z }
The constant (iota) step of IR.posToSlice: the one shape of
IR.toSlicePFunctorIota, with the empty direction assignment.
set_option linter.checkUnivs false indef posToSliceIota (o : O) :
PosToSliceSig I O (interpObjIota.{uA, uB, uI, uO} I O o)
(toSlicePFunctorIota.{uA, uB, uI, uO} I O o) :=
fun _ _ ↦ ⟨⟨⟨PUnit.unit, PEmpty.elim⟩, funext fun b ↦ PEmpty.elim b⟩, rfl⟩
The dependent sum (sigma) step of IR.posToSlice: the node's arity
element tags the subcode's shape into the coproduct of shapes.
set_option linter.checkUnivs false indef posToSliceSigma (A : Type uA)
(α : A → FreeCoprodCompDisc.Map.{max uA uB, uI, uO} I O)
(F : A → SlicePFunctor.{max uA uB uI, uB, uI, uO} I O)
(m : (a : A) → PosToSliceSig I O (α a) (F a)) :
PosToSliceSig I O (interpObjSigma I O A α)
(toSlicePFunctorSigma.{uA, uB, uI, uO} I O A F) :=
fun X z ↦
let w := m z.1 X z.2
⟨⟨⟨⟨z.1, w.1.1.1⟩, w.1.1.2⟩, w.1.2⟩, w.2⟩
The dependent product (delta) step of IR.posToSlice: the node's
recursive fields become the directions of the representable factor of the
summand at the assignment they induce, and the subcode's node the other
factor.
set_option linter.checkUnivs false indef posToSliceDelta (B : Type uB)
(α : (B → I) → FreeCoprodCompDisc.Map.{max uA uB, uI, uO} I O)
(F : (B → I) → SlicePFunctor.{max uA uB uI, uB, uI, uO} I O)
(m : (f : B → I) → PosToSliceSig I O (α f) (F f)) :
PosToSliceSig I O (interpObjDelta I O B α)
(toSlicePFunctorDelta.{uA, uB, uI, uO} I O B F) :=
fun X z ↦
let w := m (X.2 ∘ z.1) X z.2
⟨⟨⟨⟨X.2 ∘ z.1, ⟨PUnit.unit, w.1.1.1⟩⟩, Sum.elim z.1 w.1.1.2⟩,
funext fun b ↦ match b with
| Sum.inl _ => rfl
| Sum.inr d => congrFun w.1.2 d⟩,
w.2⟩
The interpretation of a code, the code's slice polynomial functor, and
the presentation of the former's nodes as the latter's, folded together.
Folding the three together is what makes the presentation computable by
IR.elim, whose computation rule is definitional, rather than by the
recursor IR.rec, whose computation rule is not: the presentation's type
mentions the other two components, so alone it has no fixed carrier.
The interpretation's object map.
The slice polynomial functor.
The presentation of an interpretation node as a functor node.
set_option linter.checkUnivs false instructure PosSlice : Type (max (uA + 1) (uB + 1) (uI + 1) uO) where interp : FreeCoprodCompDisc.Map.{max uA uB, uI, uO} I O spf : SlicePFunctor.{max uA uB uI, uB, uI, uO} I O tr : PosToSliceSig I O interp spf
The constant (iota) case of IR.posSlice.
set_option linter.checkUnivs false indef posSliceIota (o : O) : PosSlice.{uA, uB, uI, uO} I O :=
⟨interpObjIota.{uA, uB, uI, uO} I O o, toSlicePFunctorIota.{uA, uB, uI, uO} I O o,
posToSliceIota.{uA, uB, uI, uO} I O o⟩
The dependent sum (sigma) case of IR.posSlice.
set_option linter.checkUnivs false indef posSliceSigma (A : Type uA) (sub : A → PosSlice.{uA, uB, uI, uO} I O) :
PosSlice.{uA, uB, uI, uO} I O :=
⟨interpObjSigma I O A fun a ↦ (sub a).interp,
toSlicePFunctorSigma.{uA, uB, uI, uO} I O A fun a ↦ (sub a).spf,
posToSliceSigma I O A _ _ fun a ↦ (sub a).tr⟩
The dependent product (delta) case of IR.posSlice.
set_option linter.checkUnivs false indef posSliceDelta (B : Type uB) (sub : (B → I) → PosSlice.{uA, uB, uI, uO} I O) :
PosSlice.{uA, uB, uI, uO} I O :=
⟨interpObjDelta I O B fun f ↦ (sub f).interp,
toSlicePFunctorDelta.{uA, uB, uI, uO} I O B fun f ↦ (sub f).spf,
posToSliceDelta I O B _ _ fun f ↦ (sub f).tr⟩
The algebra which computes one step of IR.posSlice.
set_option linter.checkUnivs false indef posSliceAlg :
Alg.{uA, uB, uI, uO, max (uA + 1) (uB + 1) (uI + 1) uO} I O (PosSlice.{uA, uB, uI, uO} I O) :=
⟨posSliceIota.{uA, uB, uI, uO} I O, posSliceSigma I O, posSliceDelta I O⟩A code's interpretation, slice polynomial functor, and the presentation of the former's nodes as the latter's — one direction of the agreement of the two semantics established by Lemma 2 of [HancockMcBrideGhaniMalatestaAltenkirch2013].
set_option linter.checkUnivs false indef posSlice (γ : IR.{uA, uB, uI, uO} I O) : PosSlice.{uA, uB, uI, uO} I O :=
elimAlg I O (PosSlice.{uA, uB, uI, uO} I O) (posSliceAlg I O) γ
The interpretation component of IR.posSlice is IR.interpObj.
set_option linter.checkUnivs false intheorem posSlice_interp (γ : IR.{uA, uB, uI, uO} I O) :
(posSlice I O γ).interp = interpObj I O γ :=
induction I O (motive := fun γ ↦ (posSlice I O γ).interp = interpObj I O γ)
(fun s _ ih ↦ match s with
| Sum.inl _ => rfl
| Sum.inr (Sum.inl A) =>
congrArg (interpObjSigma I O A) (funext fun a ↦ ih (ULift.up a))
| Sum.inr (Sum.inr B) =>
congrArg (interpObjDelta I O B) (funext fun f ↦ ih (ULift.up f)))
γ
The functor component of IR.posSlice is IR.toSlicePFunctor.
set_option linter.checkUnivs false intheorem posSlice_spf (γ : IR.{uA, uB, uI, uO} I O) :
(posSlice I O γ).spf = toSlicePFunctor I O γ :=
induction I O (motive := fun γ ↦ (posSlice I O γ).spf = toSlicePFunctor I O γ)
(fun s _ ih ↦ match s with
| Sum.inl _ => rfl
| Sum.inr (Sum.inl A) =>
congrArg (toSlicePFunctorSigma.{uA, uB, uI, uO} I O A)
(funext fun a ↦ ih (ULift.up a))
| Sum.inr (Sum.inr B) =>
congrArg (toSlicePFunctorDelta.{uA, uB, uI, uO} I O B)
(funext fun f ↦ ih (ULift.up f)))
γend IRnamespace IRvariable (I : Type uI)
The data type an endo-code describes (the µ γ of
[HancockMcBrideGhaniMalatestaAltenkirch2013], Section 3): the W-type of
the code's slice-polynomial translation.
set_option linter.checkUnivs false indef W (γ : IR.{max uA uI, uB, uI, uI} I I) : Type (max uA uB uI) :=
SlicePFunctor.W (posSlice.{max uA uI, uB, uI, uI} I I γ).spf
The decoder of the data type an endo-code describes (the decode γ of
[HancockMcBrideGhaniMalatestaAltenkirch2013], Section 3): the slice
W-type's structure map.
set_option linter.checkUnivs false indef wDecode (γ : IR.{max uA uI, uB, uI, uI} I I) : W.{uA, uB, uI} I γ → I :=
SlicePFunctor.wIndex (posSlice.{max uA uI, uB, uI, uI} I I γ).spf
The data type and its decoder read as an object of Type/I, the
object at which the code's interpretation is taken to obtain the nodes
IR.W.mk accepts.
set_option linter.checkUnivs false indef wObj (γ : IR.{max uA uI, uB, uI, uI} I I) :
FreeCoprodCompDisc.{max uA uB uI, uI} I :=
⟨W.{uA, uB, uI} I γ, wDecode I γ⟩
The constructor of the data type an endo-code describes (the in of
[HancockMcBrideGhaniMalatestaAltenkirch2013], Section 3): a node of the
interpretation at IR.wObj, presented through IR.posSlice as a node of
the translated polynomial. IR.posSlice_interp identifies the domain
with IR.interpObj γ (IR.wObj I γ).
set_option linter.checkUnivs false indef W.mk (γ : IR.{max uA uI, uB, uI, uI} I I)
(z : ((posSlice.{max uA uI, uB, uI, uI} I I γ).interp (wObj.{uA, uB, uI} I γ)).1) :
W.{uA, uB, uI} I γ :=
SlicePFunctor.W.mk ((posSlice.{max uA uI, uB, uI, uI} I I γ).tr (wObj I γ) z).1
The decoder of a constructed element is the interpretation's decoding
of the node it was constructed from: the algebra law of IR.W.mk.
set_option linter.checkUnivs false intheorem wDecode_mk (γ : IR.{max uA uI, uB, uI, uI} I I)
(z : ((posSlice.{max uA uI, uB, uI, uI} I I γ).interp (wObj.{uA, uB, uI} I γ)).1) :
wDecode I γ (W.mk.{uA, uB, uI} I γ z) =
((posSlice I I γ).interp (wObj I γ)).2 z :=
((posSlice I I γ).tr (wObj I γ) z).2end IRend IndRec