Zulip Chat Archive

Stream: lean4

Topic: Subsingleton.elim in a def


Kyle Miller (Mar 02 2023 at 14:54):

I was having an issue where Subsingleton.elim is more powerful than you expect in a def/instance than a theorem:

def foo (β : Sort _) (x y : β) : x = y :=
  Subsingleton.elim _ _

Kyle Miller (Mar 02 2023 at 14:54):

What rule is allowing this to go through?

Yaël Dillies (Mar 02 2023 at 14:56):

Can you #print the resulting declaration? I suspect it found Subsingleton Prop and unified the universe variable with 0. All that because the body of defs is inspected for unification.

Kyle Miller (Mar 02 2023 at 14:56):

(I was thinking of leaving it as a puzzle why this isn't totally broken, but the spoiler for that is that Sort _ unifies with Prop. If you change it to Type _ it doesn't use the Subsingleton Prop instance.)

Anne Baanen (Mar 02 2023 at 14:56):

docs4#instSubsingleton

Kyle Miller (Mar 02 2023 at 14:57):

Yes, I know it's instSubsingleton that it's finding. The question is why it's ok with using this instance even though beta is a Sort ?u

Kyle Miller (Mar 02 2023 at 14:59):

This is bad for finite instances, since it can make Sort variables collapse to Prop without you realizing it.

Kyle Miller (Mar 02 2023 at 15:04):

I think it's also not very good how you can't protect against it when there's automation inside proofs inside definitions. Like, imagine that apply Subsingleton.elim is done using a mathlib3-style congr' tactic:

def foo (β : Sort _) (x y : β) : {z // x = z} :=
  y, by apply Subsingleton.elim

Eric Wieser (Mar 02 2023 at 15:05):

I think in general a lot of places where we'd write Sort _ in lean3 need to become Sort u in Lean 4

Eric Wieser (Mar 02 2023 at 15:05):

In Lean 4, the universe metavariables in variables lines are now bound per lemma, rather than globally to a free universe variable

Eric Wieser (Mar 02 2023 at 15:06):

Which means you can write variables {I : Sort _}, and still end up with all the lemmas in the file begin about I : Type u without realizing it

Kyle Miller (Mar 02 2023 at 15:10):

Ok, that's a good hint for how to resolve some subtle bugs I ran into when I was modifying convert to use Subsingleton.elim.

There were some instances that weren't being picked up anymore despite nothing seeming to involve convert (spooky action at a distance). Eventually I traced through to find the instance that didn't work, and it took too long to realize that β here specialized to Prop:

instance Equiv.finite_right {α β : Sort _} [Finite β] : Finite (α  β) :=
  Finite.of_injective Equiv.toEmbedding fun e₁ e₂ h => Equiv.ext <| by convert FunLike.congr_fun h

Kyle Miller (Mar 02 2023 at 15:10):

Is there any case where you would want a Sort _ variable to specialize to Prop?

Eric Wieser (Mar 02 2023 at 15:11):

I think in general we almost never want universe variable unification of any kind before the colon

Kyle Miller (Mar 02 2023 at 15:12):

It seems like having Sort _ or Type _ specialize to Sort n or Type n with a constant n is never what you want. But I haven't really thought about it.

Eric Wieser (Mar 02 2023 at 15:12):

And in mathlib we just use it as lazy declaration of free universe variables

Eric Wieser (Mar 02 2023 at 15:12):

Having Type _ unify to Type (max u v) is a problem we ran into a bunch in mathlib3, and we have a linter against it (more specifically, against things which use only (max u v) and not either universe variable separately)

Reid Barton (Mar 02 2023 at 17:30):

Eric Wieser said:

And in mathlib we just use it as lazy declaration of free universe variables

Yes, IMO this was always a bad practice.

Reid Barton (Mar 02 2023 at 17:35):

Does Lean 4 have implicit declaration of universe variables?

Kyle Miller (Mar 02 2023 at 17:36):

Yes, autoimplicits applies to universe variables too.

Kyle Miller (Mar 02 2023 at 17:37):

I made use of it in the fix for the issue I was having that led to this thread.

Kyle Miller (Mar 02 2023 at 17:41):

though it doesn't create fresh universe variables for types introduces via autoimplicits. Using the tactic from the linked PR, this unfortunately works:

def foo (x y : α) : x = y := by
  congr!

(but thankfully changing def -> theorem keeps it from working)

Eric Wieser (Mar 02 2023 at 17:44):

I think the problem is that people much prefer writing {R M N P Q : Type _} to {R : Type u} {M : Type v} {N : Type w} {P : Type x} {Q : Type y}

Eric Wieser (Mar 02 2023 at 17:45):

It's not {a : Type _} vs {a : Type u} that is the problem

Reid Barton (Mar 02 2023 at 17:46):

Well it's (potentially) a problem if you write Type _ when you mean Type u, but I agree it's not a problem if you know not to do that

Eric Wieser (Mar 02 2023 at 17:46):

Maybe Lean 4 could repurpose Type* as syntax for "generate new universe variables (not metavariables) for everything in this group"?

Eric Wieser (Mar 02 2023 at 17:47):

Is that easy to write as a syntax extension?

Kyle Miller (Mar 02 2023 at 17:47):

Just going back to this last foo example, note that α was introduced using autoimplicits, and apparently this is indistinguishable from doing (α : Sort _).

Reid Barton (Mar 02 2023 at 17:51):

(Unfortunately?) I think this is actually correct/desirable behavior, since it would be pretty annoying if you couldn't use autoimplicit types in combination with e.g. docs4#IO

Kyle Miller (Mar 02 2023 at 17:56):

Yeah, it also lets you introduce propositions:

example : p  q  p := Function.const _

The unfortunate part is just that something like Type* doesn't help with autoimplicit arguments, which have been seeming like a way to get around certain issues with variables. I'm not sure I've seen an example yet of these issues impacting types introduced via variable though, since you can't do induction/cases on them so tactics shouldn't touch them.

Floris van Doorn (Mar 02 2023 at 19:05):

Eric Wieser said:

Maybe Lean 4 could repurpose Type* as syntax for "generate new universe variables (not metavariables) for everything in this group"?

It's a bit limiting. I think we have plenty of cases in mathlib where we write Type _ for a bunch of types, and some of the universe variables are equal to each other. One example: you're using a category theory hom between types (potentially with extra structure).

Kyle Miller (Mar 29 2023 at 01:08):

Here's another funny example of this:

import Mathlib.Logic.Basic
theorem hmm (a b : α) : decide (a = b) = true := by simp

Yaël Dillies (Mar 29 2023 at 01:36):

Floris, I think the plenty of cases you mention are still not many. Often you only have one type, and almost everywhere away from category theory everything is fully universe-polymorphic.


Last updated: Dec 20 2023 at 11:08 UTC