Zulip Chat Archive
Stream: new members
Topic: failed to synthesize Decidable (LT)
An Qi Zhang (May 26 2025 at 02:06):
Hello, I'm trying to define a structure with 2 fields, and then show it implements an instance of DecidableLt.
I tried implementing DecidableLT for the structure, but that doesn't let me write
#eval t0 < t1 with the structure. Lean throws the error "failed to synthesize Decidable ( t0 < t1 )", but I don't know how to implement Decidable ( t0 < t1 ).
How do I implement Decidable (t0 < t1)? Or is this something Lean should be able to figure out, and I need to make a change to the definition?
Here's my MWE:
import Mathlib
namespace MWE
structure Ex where
n : Nat
b : Bool
deriving DecidableEq
def Ex.lt : Ex → Ex → Prop
| ex₁, ex₂ => (ex₁.n < ex₂.n ∨ ex₁.n = ex₂.n) ∧ (ex₁.b < ex₂.b ∨ ex₁.b = ex₂.b) ∧ ex₁ ≠ ex₂
instance Ex.instLT : (LT Ex) := {lt := Ex.lt}
instance Ex.instDecidableLt (_ _ : Ex) : (DecidableLT Ex)
| ⟨n₁,true⟩, ⟨n₂,false⟩ =>
isFalse <| by
simp[LT.lt]
simp[Ex.lt] -- Lean complains about too many recusions if merged (simp[LT.lt, Ex.lt])
| ⟨n₁, false⟩, ⟨n₂, false⟩ | ⟨n₁,true⟩, ⟨n₂,true⟩ =>
if h : n₁ < n₂ then isTrue <| by
simp[LT.lt]
simp[Ex.lt]
apply And.intro
case left =>
simp[h] -- How to make this work with Ex.lt with ex₁.n ≤ ex₂.n, instead of ex₁.n < ex₂.n ∨ ex₁.n = ex₁.n?
case right =>
intro h₁
aesop -- How to do this without aesop?
else if n₁ = n₂ then isFalse <| by
simp[LT.lt]
simp[Ex.lt]
intro h₁
cases h₁
case inl h₂ =>
contradiction
case inr h₂ =>
apply h₂
else isFalse <| by
simp[LT.lt]
simp[Ex.lt]
intro h₁
cases h₁
case inl h₂ =>
contradiction
case inr h₂ =>
apply h₂
| ⟨n₁,false⟩, ⟨n₂,true⟩ =>
if h : n₁ < n₂ then isTrue <| by
simp[LT.lt]
simp[Ex.lt]
apply Or.inl
apply h
else if h₁ : n₁ = n₂ then isTrue <| by
simp[LT.lt]
simp[Ex.lt]
aesop
else isFalse <| by
simp[LT.lt]
simp[Ex.lt]
simp[h,h₁]
aesop
def t0 : Ex := ⟨0,false⟩
def t1 : Ex := ⟨0,true⟩
-- DecidableLT Ex doesn't work?
#eval t0 < t1
-- Need to use Decidable (ex₁ < ex₂) instead of DecidableLT Ex?
instance (ex₁ ex₂ : Ex) : (Decidable (ex₁ < ex₂)) :=
inferInstanceAs (Decidable (ex₁ < ex₂)) -- failed to synthesize Decidable (ex₁ < ex₂)
Matt Diamond (May 26 2025 at 02:21):
I changed Ex.lt to abbrev to allow typeclass search to see through the definition. (I also changed the definition to use ≤.) Lean knows how to figure out the rest.
import Mathlib
namespace MWE
structure Ex where
n : Nat
b : Bool
deriving DecidableEq
abbrev Ex.lt : Ex → Ex → Prop
| ex₁, ex₂ => ex₁.n ≤ ex₂.n ∧ ex₁.b ≤ ex₂.b ∧ ex₁ ≠ ex₂
instance Ex.instLT : LT Ex := {lt := Ex.lt}
instance Ex.instDecidableRel : DecidableRel Ex.lt := inferInstance
instance Ex.instDecidableLT : DecidableLT Ex := Ex.instDecidableRel
def t0 : Ex := ⟨0,false⟩
def t1 : Ex := ⟨0,true⟩
#eval t0 < t1
Matt Diamond (May 26 2025 at 02:29):
I think adding the explicit DecidableRel instance may have helped. inferInstance doesn't seem to suffice for proving DecidableLT Ex.
Zhuanhao Z Wu (May 26 2025 at 02:48):
For your particular case, you may just model Ex.lt as a function to Boolean, and it should be easy to lift it to Ex -> Ex -> Prop:
import Mathlib
namespace MWE
structure Ex where
n : Nat
b : Bool
deriving DecidableEq
def Ex.lt : Ex → Ex → Bool
| ex₁, ex₂ => (ex₁.n < ex₂.n ∨ ex₁.n = ex₂.n) ∧ (ex₁.b < ex₂.b ∨ ex₁.b = ex₂.b) ∧ ex₁ ≠ ex₂
instance Ex.instLT : (LT Ex) := {lt := λt0 t1 => Ex.lt t0 t1}
instance Ex.instDecidableLt : (DecidableLT Ex) := by
unfold DecidableLT DecidableRel
dsimp [· < ·]
infer_instance
-- alternatively
instance (ex₁ ex₂ : Ex) : (Decidable (ex₁ < ex₂)) := by
dsimp [· < ·]
infer_instance
def t0 : Ex := ⟨0,false⟩
def t1 : Ex := ⟨0,true⟩
#eval t0 < t1
Robin Arnez (May 26 2025 at 16:29):
In the original example, the (_ _ : Ex) was the problem because they were not referenced anywhere and thus the instance synthesizer couldn't figure out what they should be.
An Qi Zhang (May 26 2025 at 17:20):
Thanks Matt and Zhuanhao! Your answers were very helpful, and also helped me with other LT instances!
@Robin Arnez Is (_ _ : Ex) the problem? If I write:
instance Ex.instDecidableLt (ex₁ ex₂ : Ex) : (DecidableLT Ex) :=
inferInstanceAs (Decidable (ex₁ < ex₂))
in place of the original:
instance Ex.instDecidableLt (_ _ : Ex) : (DecidableLT Ex)
Then Lean isn't able to synthesize the Decidable (ex₁ < ex₂)
Is there something I'm missing here?
Aaron Liu (May 26 2025 at 17:27):
You want instance Ex.instDecidableLt : (DecidableLT Ex)
Aaron Liu (May 26 2025 at 17:31):
DecidableLT Ex is an abbrev for ∀ (a b : Ex), Decidable (a < b)
Last updated: Dec 20 2025 at 21:32 UTC