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.W

Codes for small indexed induction-recursion

IIR I D J E is the type of codes for small indexed inductive-recursive definitions, Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013]. Where an IR code describes one inductive-recursive definition, an IIR code describes a family of them, indexed by I on the way in and J on the way out, with D and E the type each decodes into at each index. Two things change from IR: the constant code IIR.iota names the output index it lands at as well as the value it decodes to, and the dependent product code IIR.delta carries an index assignment ix, choosing the input index of each of its recursive fields. IR is the fragment in which I and J are singletons.

Codes are presented as the W-type of a polynomial functor IIR.pFunctor, following IR (Geb/Mathlib/Data/PFunctor/IndRec/Basic.lean).

The reduction of small indexed induction-recursion to small induction-recursion is IIR.toIR, the ⌊·⌋ of Section 6: a code over I/J with decodings D/E becomes a plain code over the total spaces Σ i, D i and Σ j, E j. Through it, the data type and decoder an endo-code describes are derived from those of an IR code (Geb/Mathlib/Data/PFunctor/IndRec/W.lean) by cutting into fibres over the index.

Main definitions

    IIR.pFunctor — the polynomial functor whose W-type defines codes: shapes IIR.Shape, directions IIR.Direction.

    IIR, IIR.mk — the type of codes and its constructor.

    IIR.iota, IIR.sigma, IIR.delta — the code constructors, one per shape, and IIR.delta1 the single-recursive-field special case of IIR.delta (the δ₁ of Section 6).

    IIR.Obj, IIR.Alg, IIR.Alg.toHom, IIR.elim, IIR.elimAlg — the polynomial functor's interpretation, the pattern-matched form of an algebra of it, and the eliminator.

    IIR.FamSlice — the base category's objects: a family, over the index type, of objects of the slice over that index's decoding type.

    IIR.interpAlg, IIR.interp — the direct interpretation of a code as a functor between such families, the ⟦·⟧_IIR of Section 6.

    IIR.toIRAlg, IIR.toIR — the reduction to IR codes, the ⌊·⌋ of Section 6.

    IIR.W, IIR.wDecode — the indexed family of data types an endo-code describes and their decoders, cut out of IR.W and IR.wDecode of the reduced code.

Main statements

    IIR.elimAlg_iota, IIR.elimAlg_sigma, IIR.elimAlg_delta — the computation rules of IIR.elimAlg, all definitional.

Implementation notes

IIR.delta's shape carries the index assignment as well as the arity, since the directions — the tuples of decodings the continuation receives — depend on it; the shape type's third summand is accordingly Σ P : Type uB, P → I rather than Type uB.

The reduction IIR.toIR carries IIR.iota and IIR.sigma across unchanged. Its work is in the IIR.delta clause: a recursive field of the reduced code decodes to a pair of an index and a value, so the reduction cannot ask for a field at a chosen index. It takes the fields wherever they land and adds an IR.sigma over the proof that they landed at the indices ix demands — the σ (i ≡ π₀ ∘ iD) of Section 6 — which is then what transports the values into the types the continuation expects. The condition is stated pointwise rather than as an equality of the two index assignments, so that building one needs no functional extensionality. It is embedded into Type uA as ULift (PLift ...), following IR.sliceCode.

IIR.W is stated for codes at IIR.{max uA uI uD, uB, uI, uD, uI, uD}, the instance at which the reduced code meets the universe condition of IR.W. It carries no constructor of its own: an element is an element of the reduced code's data type, built by IR.W.mk, together with the proof that it decoded to the index of the fibre. The index constraints the reduction introduces appear there as data — the proof that each recursive field landed where the index assignment demands.

The correspondence between IIR.interp and the interpretation of IIR.toIR — Section 6's remark that the two agree up to the equivalences among (i : I) → Set/(D i), Σ D → Set and Set/Σ D — is not formalized here.

References

    [HancockMcBrideGhaniMalatestaAltenkirch2013]

Tags

indexed induction-recursion, inductive-recursive, polynomial functor, W-type, initial algebra

@[expose] public sectionuniverse uA uB uI uD uJ uEnamespace IndRecopen CategoryTheoryvariable (I : Type uI) (D : I Type uD) (J : Type uJ) (E : J Type uE)namespace IIR

The shape type of the polynomial functor whose W-type defines codes for small indexed inductive-recursive types: an output index paired with a decoding, a non-recursive arity, or a recursive arity with an index assignment.

set_option linter.checkUnivs false indef Shape : Type (max (uA + 1) (uB + 1) uI uJ uE) := (Σ j : J, E j) Type uA (Σ P : Type uB, P I)

The direction type of the polynomial functor whose W-type defines codes for small indexed inductive-recursive types. A delta shape's directions are the tuples of decodings its recursive fields deliver, at the input indices its index assignment chooses.

set_option linter.checkUnivs false indef Direction : Shape.{uA, uB, uI, uJ, uE} I J E Type (max uA uB uD) := Sum.elim (fun _ PEmpty) (Sum.elim (fun A ULift.{max uB uD} A) (fun x ULift.{uA} ((p : x.1) D (x.2 p))))

The polynomial functor whose W-type defines codes for small indexed inductive-recursive types.

set_option linter.checkUnivs false indef pFunctor : PFunctor.{max (uA + 1) (uB + 1) uI uJ uE, max uA uB uD} := Shape.{uA, uB, uI, uJ, uE} I J E, Direction I D J E

The value at V of the interpretation of IIR.pFunctor as an endofunctor on Type.

set_option linter.checkUnivs false indef Obj.{v} (V : Type v) : Type (max (uA + 1) (uB + 1) uI uD uJ uE v) := PFunctor.Obj (pFunctor.{uA, uB, uI, uD, uJ, uE} I D J E) V

A pattern-matched form of an algebra of IIR.pFunctor: one clause per code constructor.

set_option linter.checkUnivs false indef Alg.{v} (V : Type v) : Type (max (uA + 1) (uB + 1) uI uD uJ uE v) := ((Σ j : J, E j) V) × ((A : Type uA) (A V) V) × ((P : Type uB) (ix : P I) (((p : P) D (ix p)) V) V)

Convert IIR.Alg to the morphism form of an algebra of IIR.pFunctor.

set_option linter.checkUnivs false indef Alg.toHom.{v} (V : Type v) (alg : Alg.{uA, uB, uI, uD, uJ, uE, v} I D J E V) : Obj.{uA, uB, uI, uD, uJ, uE, v} I D J E V V := fun s, ds match s with | Sum.inl je => alg.1 je | Sum.inr (Sum.inl (A : Type uA)) => alg.2.1 A (ds ULift.up) | Sum.inr (Sum.inr x) => alg.2.2 x.1 x.2 (ds ULift.up)
end IIR

The type of codes for small indexed inductive-recursive definitions (Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013]): the W-type of IIR.pFunctor.

set_option linter.checkUnivs false indef IIR : Type (max (uA + 1) (uB + 1) uI uD uJ uE) := PFunctor.W (IIR.pFunctor.{uA, uB, uI, uD, uJ, uE} I D J E)
namespace IIR

The constructor for IIR.

def mk (s : Shape.{uA, uB, uI, uJ, uE} I J E) (d : Direction I D J E s IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E := WType.mk s d

The constant (iota) code: no subcodes; the node lands at the output index m and decodes to ev.

def iota (m : J) (ev : E m) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E := mk I D J E (Sum.inl m, ev) PEmpty.elim

The dependent sum (sigma) code: a non-recursive field of type A, then the subcode it selects.

def sigma (A : Type uA) (c : A IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E := mk I D J E (Sum.inr (Sum.inl A)) (c ULift.down)

The dependent product (delta) code: a P-indexed family of recursive fields, the field at p taken at input index ix p, whose decodings the subcode assignment c receives.

def delta (P : Type uB) (ix : P I) (c : ((p : P) D (ix p)) IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E := mk I D J E (Sum.inr (Sum.inr P, ix)) (c ULift.down)

A single recursive field at the input index n, presented as a PUnit-indexed family: the δ₁ of Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013]. Its continuation receives that field's decoded value, which is what lets the shape of the rest of the node depend on it.

def delta1 (n : I) (c : D n IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E := delta I D J E PUnit (fun _ n) fun dv c (dv PUnit.unit)

The eliminator (the algebra morphism from the initial algebra) for IIR, taking the algebra in morphism form.

def elim.{v} (V : Type v) (alg : Obj.{uA, uB, uI, uD, uJ, uE, v} I D J E V V) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E V := WType.elim V alg

The eliminator for IIR, taking the algebra in the IIR.Alg form.

def elimAlg.{v} (V : Type v) (alg : Alg.{uA, uB, uI, uD, uJ, uE, v} I D J E V) : IIR.{uA, uB, uI, uD, uJ, uE} I D J E V := elim I D J E V (Alg.toHom I D J E V alg)

Computation rule for IIR.elimAlg at IIR.iota (definitional).

theorem elimAlg_iota.{v} (V : Type v) (alg : Alg.{uA, uB, uI, uD, uJ, uE, v} I D J E V) (m : J) (ev : E m) : elimAlg I D J E V alg (iota I D J E m ev) = alg.1 m, ev := rfl

Computation rule for IIR.elimAlg at IIR.sigma (definitional).

theorem elimAlg_sigma.{v} (V : Type v) (alg : Alg.{uA, uB, uI, uD, uJ, uE, v} I D J E V) (A : Type uA) (c : A IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : elimAlg I D J E V alg (sigma I D J E A c) = alg.2.1 A fun a elimAlg I D J E V alg (c a) := rfl

Computation rule for IIR.elimAlg at IIR.delta (definitional).

theorem elimAlg_delta.{v} (V : Type v) (alg : Alg.{uA, uB, uI, uD, uJ, uE, v} I D J E V) (P : Type uB) (ix : P I) (c : ((p : P) D (ix p)) IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : elimAlg I D J E V alg (delta I D J E P ix c) = alg.2.2 P ix fun dv elimAlg I D J E V alg (c dv) := rfl

The objects of the base category of small indexed induction-recursion: a family, over the index type I, of objects of the slice over that index's decoding type D i.

set_option linter.checkUnivs false indef FamSlice : Type (max (uA + 1) (uB + 1) uI uD) := (n : I) FreeCoprodCompDisc.{max uA uB, uD} (D n)

The algebra which computes one step of the direct interpretation of an IIR code as a functor between families of slices (the ⟦·⟧_IIR of Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013]). A constant code contributes only the proof that it landed at the index asked for, and decodes by transporting its value along that proof.

set_option linter.checkUnivs false indef interpAlg : Alg.{uA, uB, uI, uD, uJ, uE, max (uA + 1) (uB + 1) uI uD uJ uE} I D J E (FamSlice.{uA, uB, uI, uD} I D FamSlice.{uA, uB, uJ, uE} J E) := fun je _ n ULift.{max uA uB} (PLift (je.1 = n)), fun q q.down.down je.2, fun A sub G n FreeCoprodCompDisc.coprod (E n) A fun a sub a G n, fun P ix sub G n FreeCoprodCompDisc.coprod (E n) ((p : P) (G (ix p)).1) fun ig sub (fun p (G (ix p)).2 (ig p)) G n

The direct interpretation of an IIR code as a functor between families of slices: the ⟦·⟧_IIR of Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013].

set_option linter.checkUnivs false indef interp (c : IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : FamSlice.{uA, uB, uI, uD} I D FamSlice.{uA, uB, uJ, uE} J E := elimAlg I D J E _ (interpAlg I D J E) c

The algebra which computes one step of the reduction of IIR codes to IR codes over the total spaces (the ⌊·⌋ of Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013]).

set_option linter.checkUnivs false indef toIRAlg : Alg.{uA, uB, uI, uD, uJ, uE, max (uA + 1) (uB + 1) uI uD uJ uE} I D J E (IR.{uA, uB, max uI uD, max uJ uE} (Σ i, D i) (Σ j, E j)) := IR.iota (Σ i, D i) (Σ j, E j), IR.sigma (Σ i, D i) (Σ j, E j), fun P ix c IR.delta (Σ i, D i) (Σ j, E j) P fun iD IR.sigma (Σ i, D i) (Σ j, E j) (ULift.{uA} (PLift ( p, (iD p).1 = ix p))) fun h c fun p h.down.down p (iD p).2

The reduction of an IIR code to an IR code over the total spaces: the ⌊·⌋ of Section 6 of [HancockMcBrideGhaniMalatestaAltenkirch2013].

set_option linter.checkUnivs false indef toIR (c : IIR.{uA, uB, uI, uD, uJ, uE} I D J E) : IR.{uA, uB, max uI uD, max uJ uE} (Σ i, D i) (Σ j, E j) := elimAlg I D J E _ (toIRAlg I D J E) c
end IIRnamespace IIR

The indexed family of data types an endo-code describes: the data type of the reduced IR code, cut into fibres over the index.

set_option linter.checkUnivs false indef W (c : IIR.{max uA uI uD, uB, uI, uD, uI, uD} I D I D) (n : I) : Type (max uA uB uI uD) := { x : IR.W.{uA, uB, max uI uD} (Σ i, D i) (toIR I D I D c) // (IR.wDecode (Σ i, D i) (toIR I D I D c) x).1 = n }

The decoders of the indexed family of data types an endo-code describes: the value component of the reduced code's decoding, transported along the fibre's index proof.

set_option linter.checkUnivs false indef wDecode (c : IIR.{max uA uI uD, uB, uI, uD, uI, uD} I D I D) (n : I) (x : W.{uA, uB, uI, uD} I D c n) : D n := x.2 (IR.wDecode (Σ i, D i) (toIR I D I D c) x.1).2
end IIRend IndRec