Zulip Chat Archive
Stream: lean4
Topic: Unification issue involving OfNat
Tomas Skrivan (Dec 07 2022 at 22:31):
I have a typeclass depending on Nat
and I'm having some troubles when using constants like 0
or 1
. Somehow there is a difference when I write 0
vs Nat.zero
or 1
vs Nat.zero.succ
.
class Uncurry (n : Nat) (F : Type) where
{Y : Type} {Xs : Type}
uncurry : F → Xs → Y
instance (priority := low) uncurry_zero {X : Type} : Uncurry 0 X where
uncurry := λ (x : X) (_ : Unit) => x
instance uncurry_succ {X Y : Type} [inst : Uncurry n Y] : Uncurry (n+1) (X → Y) where
Xs := X×inst.Xs
Y := inst.Y
uncurry := λ f (x,xs) => Uncurry.uncurry (f x) xs
-- Error: failed to synthesize instance Uncurry Nat.zero X
example {X : Type} : Uncurry Nat.zero X := by infer_instance -- error
example {X : Type} : Uncurry Nat.zero X := uncurry_zero -- works
-- This works
example {X Y Z : Type} : Uncurry Nat.zero.succ.succ (X → Y → Z) := by infer_instance
example {X Y Z : Type} : Uncurry Nat.zero.succ.succ (X → Y → Z) := uncurry_succ
What is going on here?
Gabriel Ebner (Dec 07 2022 at 23:11):
Here is a short version:
class Foo (n : Nat)
instance : Foo 0 where
example : Foo .zero := inferInstance -- fails
The short answer is that Nat.zero
and 0
are different functions.
Gabriel Ebner (Dec 07 2022 at 23:11):
You can tell the discrimination tree index to ignore the function symbol here:
class Foo (n : Nat)
instance : Foo (no_index 0) where
example : Foo .zero := inferInstance -- works
Gabriel Ebner (Dec 07 2022 at 23:13):
BTW, I would avoid type fields in classes:
class Uncurry (n : Nat) (F : Sort u) (Y : outParam (Sort v)) (Xs : outParam (Sort w)) where
uncurry : F → Xs → Y
And the (priority := low)
has no effect in your snippet.
Tomas Skrivan (Dec 08 2022 at 15:06):
I see, makes sense.
However, I do not understand what no_index
is doing. I see that in core it is used exactly when mixing Nat and and instances. Also somewhere in the code there is a comment that instances are not indexed. But I still do not understand what it is doing.
Thanks for the suggestions, using outParam is a good idea. That way I don't have to mark everything reducible as I had to when I started using this class.
Jannis Limperg (Dec 08 2022 at 15:19):
no_index X
tells the indexing machinery to ignore X
. So the instance will be tried on any typeclass problem of the form Foo ?
, rather than just on problems of the form Foo 0
. At that point, unification can kick in and confirm that 0 = Nat.zero
.
Tomas Skrivan (Dec 08 2022 at 16:37):
Makes perfect sense! Thanks for the explanation.
Last updated: Dec 20 2023 at 11:08 UTC