Zulip Chat Archive
Stream: new members
Topic: cannot infer universe when declaring instances
LizBonn (Jan 20 2025 at 12:22):
I'm trying to achieve something like peano axioms in Lean. More precisely, I create a type class called NatLike
and NatLike α
means that α
satisfies peano axioms. The definition of NatLike
is as follows:
class NatLike.{u, v} (α : Type u) where
zero : α
succ : α → α
eq_iff_succ_eq_succ : ∀ {b c : α}, b = c ↔ succ b = succ c
zero_ne_succ : ∀ a : α, zero ≠ succ a
inductionLike : {motive : α → Sort v} → motive zero → ((a : α) → motive a → motive (succ a)) → (a : α) → motive a
Similar to Nat.le
, I also define the le
relationship on a type α
with instance NatLike α
:
inductive NatLike.le.{u} {α : Type u} [NatLike α] : α → α → Prop where
| refl (n : α) : le n n
| step (n m : α) : le n m → le n (NatLike.succ m)
Then I want to prove NatLike.zero_le : (n : α) → le zero n
using inductionLike
:
theorem NatLike.zero_le.{u} {α : Type u} [h : NatLike α] (n : α) : NatLike.le NatLike.zero n :=
inductionLike (motive := fun x : α => le zero x)
(le.refl zero) (fun n hle => le.step zero n hle) n
But there're some errors!! Lean complains that it fails to synthesize NatLike α
. So I provide all the implicit parameters:
theorem NatLike.zero_le'.{u} {α : Type u} [h : NatLike α] (n : α) : NatLike.le NatLike.zero n :=
@NatLike.inductionLike α h (motive := fun n : α => @NatLike.le α h (@NatLike.zero α h) n)
(@NatLike.le.refl α h (@NatLike.zero α h)) (fun n hle => @NatLike.le.step α h (@NatLike.zero α h) n hle) n
After that, Lean finds a type mismatch:
type mismatch
le zero n
has type
Prop : Type
but is expected to have type
Sort u_1 : Type u_1
However, when I #check
the same expression, the errors miraculously disappear:
section
universe u
variable {α : Type u} [h : NatLike α] (n : α)
#check @NatLike.inductionLike α h (motive := fun n : α => @NatLike.le α h (@NatLike.zero α h) n) (@NatLike.le.refl α h (@NatLike.zero α h)) (fun n hle => @NatLike.le.step α h (@NatLike.zero α h) n hle) n
end
This makes me really confused. I guess it's probably because I introduce an arbitrary universe v
when defining NatLike
and Lean cannot infer what v
is from a given instance like NatLike α
. When I change the type of the motive to α → Prop
, everything is OK as expected. But on one hand, I want to define the induction to be some general like Nat.rec
and on the other hand, when I try to prove the decidability of the le
relationship, I need to do induction on Decidable
which is not a Prop
.
So, is my guess right? And if I want to eliminate a type α
with instance NatLike α
to any other universe, how should I define the type of inductionLike
? I mean, how to express "for any motive : α → Sort v
, ..."? Or does such an expression make no sense at all?
Any explanation will be appreciated. Thanks in advance!
Riccardo Brasca (Jan 20 2025 at 12:36):
(deleted)
Riccardo Brasca (Jan 20 2025 at 12:38):
(deleted)
Riccardo Brasca (Jan 20 2025 at 12:39):
No sorry, I am confused
Riccardo Brasca (Jan 20 2025 at 12:51):
Yeah, it is something subtle about universes. Your NatLike.{u, v}
fixes v
. If you write set_option pp.universes true
before your theorem you see that h
has type NatLike.{u, u_1} α
, so if u_1
is not Prop
is not good.
Riccardo Brasca (Jan 20 2025 at 12:51):
I am not sure how this can be fixed in general.
Riccardo Brasca (Jan 20 2025 at 12:53):
I mean
theorem NatLike.zero_le.{u} {α : Type u} [h : NatLike.{u, 0} α] (n : α) : NatLike.le NatLike.zero n :=
inductionLike (motive := fun x : α => le zero x)
(le.refl zero) (fun n hle => le.step zero n hle) n
works. The problem is that you want NatLike
to work for an arbitrary v
, but it is impossible to quantify over universes.
LizBonn (Jan 20 2025 at 13:02):
Yeah, I get this. But as stated above, when I want to do induction on Decidable
, I may need an instance like NatLike.{u, 1} α
because Decidable
has type Type
. So now my question is, given a concrete type α : Type u
, as long as I give an instance NatLike.{u, v} α
for any universe v
, can we directly derive instances such as NatLike.{u, 0} α
and NatLike.{u, 1} α
from it?
LizBonn (Jan 20 2025 at 13:04):
Or do I have to give different instances separately when in difference universes v
?
Riccardo Brasca (Jan 20 2025 at 13:05):
But then the various zero
would be different, right?
Eric Wieser (Jan 20 2025 at 13:06):
Yes, you'd need
class NatLike.{u} (α : Type u) where
zero : α
succ : α → α
eq_iff_succ_eq_succ : ∀ {b c : α}, b = c ↔ succ b = succ c
zero_ne_succ : ∀ a : α, zero ≠ succ a
class NatLikeRec.{v, u} (α : Type u) [NatLike α] where
inductionLike : {motive : α → Sort v} → motive NatLike.zero → ((a : α) → motive a → motive (NatLike.succ a)) → (a : α) → motive a
Eric Wieser (Jan 20 2025 at 13:07):
(note that NatLikeRec
also needs that inductionLike p0 psucc zero = p0
and inductionLike p0 psucc (succ n) = ...
)
LizBonn (Jan 20 2025 at 13:11):
Uh, sorry, I'm stupid. I can only give an instance for a fixed universe v
, as what we talked above.
LizBonn (Jan 20 2025 at 13:14):
I understand that. Thank you very much!!
Riccardo Brasca (Jan 20 2025 at 13:15):
Yeah, that's the problem with your approach (and in general this is the reason why we try to avoid using universal properties like that in definitions). I think you may be able to define an instance NatLike.{u, v_1} α → NatLike.{u, v_2} α → NatLike.{u, max v_1 v_2} α
playing with Ulift
, but I am not 100% sure.
LizBonn (Jan 20 2025 at 13:17):
That sounds reasonable, I'll try it.
Eric Wieser (Jan 20 2025 at 13:31):
What you can do here is just have the recursor go into Type
, and then use the real Nat
to lift it to other universes
Last updated: May 02 2025 at 03:31 UTC