Zulip Chat Archive

Stream: new members

Topic: Can't understand universes in inductives


Jakub Nowak (Dec 02 2025 at 15:55):

If I write:

inductive Foo : Type  Type where
| nil : {α : Type}  Foo α

then Lean accepts this without errors.

But when I add constructor like this:

inductive Foo : Type  Type where
| nil : {α : Type}  Foo α
| cons : {α β : Type}  (α  Foo β)  Foo β

then now I get error about universes in constructor nil which worked fine before.

What's going on?

Aaron Liu (Dec 02 2025 at 15:56):

that's because the index is not being promoted to a parameter anymore

Aaron Liu (Dec 02 2025 at 15:58):

Since you can rewrite the first Foo as

inductive Foo (α : Type) : Type where
| nil : Foo α

But you can't do the same kind of thing for the other Foo

Jakub Nowak (Dec 02 2025 at 16:00):

I see. That's kinda confusing, is there a reason why Lean does that automatic promotion of indexes to parameters?

Aaron Liu (Dec 02 2025 at 16:00):

it's so you don't get the error on a perfectly reasonable inductive

Jakub Nowak (Dec 02 2025 at 16:01):

Is it reasonable though? It seems like it's impossible to write inductive with signature Type → Type unless the argument is a parameter.

Aaron Liu (Dec 02 2025 at 16:03):

so it's fine if the argument is a parameter

Kenny Lau (Dec 02 2025 at 16:05):

@Jakub Nowak Foo β must contain cons f for any function f : α → Foo β for any α : Type!! Surely that is too big for something in Type

Jakub Nowak (Dec 02 2025 at 16:05):

Actually, I think that

inductive Foo (α : Type) : Type where
| nil : Foo α

and

inductive Foo : Type  Type where
| nil : (α : Type)  Foo α

aren't the same.

In first case α is a parameter of Foo, while in second, it's a parameter of Foo.nil.

Aaron Liu (Dec 02 2025 at 16:09):

comparison:

inductive Foo (α : Type) : Type where
| nil : Foo α

/--
info: inductive Foo : Type → Type
number of parameters: 1
constructors:
Foo.nil : {α : Type} → Foo α
-/
#guard_msgs in
#print Foo

and the other one

inductive Foo : Type  Type where
| nil : (α : Type)  Foo α

/--
info: inductive Foo : Type → Type
number of parameters: 1
constructors:
Foo.nil : (α : Type) → Foo α
-/
#guard_msgs in
#print Foo

Aaron Liu (Dec 02 2025 at 16:09):

so I think they're basically the same

Kenny Lau (Dec 02 2025 at 16:14):

@Jakub Nowak in both cases, each Foo α just contains .nil and nothing else


Last updated: Dec 20 2025 at 21:32 UTC