Zulip Chat Archive
Stream: general
Topic: Proving DecidableEq of inductive type recursively using it
Juneyoung Lee (Sep 11 2025 at 22:06):
Hello everyone,
How can I prove DecidableEq of an inductive data type using itself in one of constructors as a list, for example:
inductive TestTy where
| case1 | case2 (t:List TestTy)
deriving DecidableEq
... without defining a separate boolean equality function on TestTy?
I gave a small try, but this didn't seem to work because comparing two lists already needed DecidableEq on TestTy:
instance : DecidableEq TestTy := fun a b =>
match a, b with
| .case1, .case1 => by simp; exact inferInstance
| .case2 i1, .case2 i2 =>
if h: i1 = i2 then isTrue (by rw [h]) <- This doesn't work because equality of two TestTy lists isn't decidable yet
else isFalse (fun h_eq => TestTy.noConfusion h_eq (fun h2 => absurd h2 h))
| .. (omit)
Kenny Lau (Sep 11 2025 at 22:27):
i don't know what the state of the art is, but i don't see the harm of defining a separate boolean equality
(obviously the right response is to hope some lean developers have the time and interest to tackle this problem)
Kenny Lau (Sep 11 2025 at 22:27):
(or maybe you could get into metaprogramming and write a stronger deriver and get it into mathlib :slight_smile:)
Aaron Liu (Sep 11 2025 at 22:52):
here we go
inductive TestTy where
| case1 | case2 (t:List TestTy)
mutual
def TestTy.decEq (a b : TestTy) : Decidable (a = b) :=
match a with
| .case1 =>
match b with
| .case1 => .isTrue rfl
| .case2 _ => .isFalse TestTy.noConfusion
| .case2 as =>
match b with
| .case1 => .isFalse TestTy.noConfusion
| .case2 bs =>
match TestTy.decEqList as bs with
| .isTrue h => .isTrue (congrArg TestTy.case2 h)
| .isFalse h => .isFalse fun hc => h (TestTy.case2.inj hc)
def TestTy.decEqList (as bs : List TestTy) : Decidable (as = bs) :=
match as with
| [] =>
match bs with
| [] => .isTrue rfl
| _ :: _ => .isFalse List.noConfusion
| a :: as =>
match bs with
| [] => .isFalse List.noConfusion
| b :: bs =>
match TestTy.decEq a b with
| .isTrue hab =>
match TestTy.decEqList as bs with
| .isTrue hss => .isTrue (congr (congrArg List.cons hab) hss)
| .isFalse h => .isFalse fun hc => h (List.cons.inj hc).2
| .isFalse h => .isFalse fun hc => h (List.cons.inj hc).1
end
Kenny Lau (Sep 11 2025 at 23:17):
oh boy, mutual
Aaron Liu (Sep 11 2025 at 23:19):
the other option uses well-founded recursion
Aaron Liu (Sep 11 2025 at 23:20):
which is irreducible so you can't decide things
Juneyoung Lee (Sep 12 2025 at 13:20):
That was fast! :) Thank you all.
Last updated: Dec 20 2025 at 21:32 UTC