Zulip Chat Archive
Stream: lean4
Topic: Local definitions in mutual inductive type block
Avi Craimer (Sep 12 2022 at 16:17):
@Mario Carneiro @Tomas Skrivan
Mario, I'm not sure I can give a minimum working example, because I can't get it to work :wink:
However, I've tried to separate the data from the constaint checking. For the data I've used a structure with a generic type variable, and then I use a recursive function to figure out the correct nested type.
structure MorphData (d:Nat) (α :Type u) where
name: Name
input: α
output: α
def MorphDataT (d:Nat) :=
match d with
| 0 => MorphData 0 {⋆}
| nonZero => MorphData nonZero (MorphDataT (nonZero - 1))
It's obvious to me that this recursion terminates, but I get an error,
fail to show termination for
MorphDataT
with errors
argument #1 was not used for structural recursion
failed to eliminate recursive application
MorphDataT (nonZero - 1)
However, I don't know what to put in the termination_by clause. I searched for examples, but the obvious things don't work. I need to say that d will keep getting smaller until it terminates upon reaching zero,
A good general learning point for me would be this. Is there a way to print the proposition that needs to be proven to prove recursion for a function that is not itself a theorem?
Mario Carneiro (Sep 12 2022 at 16:20):
The easiest way to fix this particular error is to use n + 1
instead of n
in the nonzero case
Mario Carneiro (Sep 12 2022 at 16:41):
If I understand your construction correctly, this should do what you want:
inductive RawMorph : Nat → Type u where
| unit : RawMorph 0
| pair (nm : Name) (i : RawMorph n) (o : RawMorph n) : RawMorph (n+1)
inductive RawMorph.isGlobular : RawMorph n → Prop
| unit : RawMorph.isGlobular .unit
| self {i : RawMorph n} : i.isGlobular → (i.pair nm i).isGlobular
| parallel {i o : RawMorph n} :
(i.pair nm₁ o).isGlobular → (i.pair nm₃ o).isGlobular →
((i.pair nm₁ o).pair nm₂ (i.pair nm₃ o)).isGlobular
def Morph (n) := { m : RawMorph n // m.isGlobular }
Avi Craimer (Sep 12 2022 at 17:05):
Thanks for the code example. I don't entirely understand it, but I'll try to figure it out.
My own version is progressing. With the recursive morphism data structure type I can eliminate the mutual recursion between Constraint and MorphSym. Since they both depend only on MorphData.
structure MorphData (d:Nat) (α :Type u) where
name: Name
input: α
output: α
deriving Repr
def MorphDataT (d:Nat) :=
match d with
| 0 => MorphData 0 {⋆}
| n + 1 => MorphData d (MorphDataT (n))
inductive Constraint : Type u :=
| globular (d:Nat) (input: MorphDataT d) (output: MorphDataT d) (p:(input = output) ∨ (input.input = output.input ∧ input.output = output.output)) : Constraint
However, now I get the error:
input : MorphDataT d
invalid field 'input', the environment does not contain 'MorphDataT.input'
input
has type
MorphDataT dLean
I'm guessing this is because the type checker doesn't resolve MorphDataT d
to the type it returns. Is there some flag I should add to MorphDataT to tell the compiler to replace it with the actual type it returns?
Avi Craimer (Sep 13 2022 at 16:53):
@Mario Carneiro Thanks again. I managed to adapt and build on the code sample you posted above. I think I see how to do what I wanted to do now. If I understand correctly, the basic strategy is have a "raw" type that gives you all the values with their basic shape but without propositional constraints on which ones can be formed. Then use subtyping to form the actual set of relevant values. Is this a common pattern?
I was also curious to know what the difference is between using a Sigma type and using the { _ // _ } notation. At first I assumed the { _ // _ } notation must be syntactic sugar for a Sigma type, but it seems to produce something different.
Mario Carneiro (Sep 13 2022 at 17:50):
The difference between Sigma
and Subtype
is that one takes A : Type
and B : A -> Type
and the other takes A : Type
and p : A -> Prop
Jason Rute (Sep 13 2022 at 17:51):
@Avi Craimer See docs#sigma and docs#subtype (Lean 3 but I doubt it is different in Lean 4).
Avi Craimer (Sep 13 2022 at 20:53):
Alright, I understand now. If I want to filter our certain elements with a proposition use Subtype, if I want a dependent product where the second value can be more than a singleton use Sigma.
Last updated: Dec 20 2023 at 11:08 UTC