Zulip Chat Archive

Stream: general

Topic: Rewrite with <- vs symm


Bolton Bailey (Oct 18 2021 at 21:05):

This is something I encountered a while ago, but I don't think I've posted about it before. Can someone offer an explanation of why the first rewrite works, but the second, which seems like it is applying an equivalent transformation, does not? This arose because I was trying to switch a simp statement that looked like simp only [<-finset.mul_sum] with my_attribute to one where my_mul_sum was included in the attribute in order to make it look a little cleaner.

import algebra.big_operators.ring

open_locale big_operators classical

section

universes u v

parameter {F : Type u}
parameter [field F]

lemma my_mul_sum {α : Type u} {β : Type v} {s : finset α} {b : β} {f : α  β}
  [non_unital_non_assoc_semiring β] :
   (x : α) in s, b * f x = b *  (x : α) in s, f x := finset.mul_sum.symm

example (n : ) (a : F) (b : fin n -> F) : ( (i : fin n) in finset.fin_range n, a * b i) = 0 :=
begin
  -- rw <-finset.mul_sum, -- works fine
  rw my_mul_sum, -- this fails where above succeeds
end

end

Kyle Miller (Oct 18 2021 at 21:20):

I tried specializing my_mul_sum to see what's going wrong, but I'm confused about this error:

example (n : ) (a : F) (b : fin n -> F) : ( (i : fin n) in finset.fin_range n, a * b i) = 0 :=
begin
  have := @my_mul_sum (fin n),
/-
20:12: type mismatch at application
  my_mul_sum
term
  fin n
has type
  Type : Type 1
but is expected to have type
  Type u : Type (u+1)
-/
end

Kyle Miller (Oct 18 2021 at 21:21):

Oh, the problem is that universes is inside the section. Bring it outside the section, and the rewrite goes through.

Yaël Dillies (Oct 18 2021 at 21:21):

Elaboration issue?

Floris van Doorn (Oct 18 2021 at 21:21):

Replace the line universes u v by universe variables u v. That should fix the issue.

I've mentioned a couple times that I think universes should never be used, and always be replaced by universe variables. However, somehow universes has become the de factor standard in mathlib (I think). [EDIT: it seems that as long as you're outside a section it doesn't matter]

The difference between the two is that universes fixes the universes for the section. So the lemma my_mul_sum can only be applied to α living in the (fixed) universe parameter u, not to a type living in any other universe (at least until the end of the section/namespace/file). universe parameter generalizes the universes immediately, so the lemma my_mul_sum is available immediately to any type in any universe desired (which is usually what you want, even though it rarely makes a difference).

Yaël Dillies (Oct 18 2021 at 21:21):

Oh no, the dreaded universes-section interaction :fear:

Floris van Doorn (Oct 18 2021 at 21:22):

Oh, if we use universes outside a section does it behave the same as universe variable?

Yaël Dillies (Oct 18 2021 at 21:23):

I think so, yeah. We do all the time without any trouble as far as I know.

Yaël Dillies (Oct 18 2021 at 21:23):

Bhavik and I had a funky example with an added layer of complexity using namespace.

Floris van Doorn (Oct 18 2021 at 21:23):

I thought the "without any trouble" was just because you rarely apply a lemma to a type in a different universe. But I guess it's not that uncommon.

Yaël Dillies (Oct 18 2021 at 21:25):

Here it is: https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/section.2C.20universe.2C.20namespace.20deadly.20interaction/near/241180594

Yaël Dillies (Oct 18 2021 at 21:25):

I didn't know what you just explained at the time, so you might well be right.

Riccardo Brasca (Oct 18 2021 at 21:25):

Is there a difference between variable and parameter?

Yaël Dillies (Oct 18 2021 at 21:25):

Yes.

Floris van Doorn (Oct 18 2021 at 21:26):

Parameters are "fixed" for the section: you can only apply the lemmas (in that section) to that parameter, not any other value.

Yaël Dillies (Oct 18 2021 at 21:26):

parameter appends silently the arguments to any call of the defs/lemmas within the same section.

Mario Carneiro (Oct 18 2021 at 21:26):

Floris van Doorn said:

The difference between the two is that universes fixes the universes for the section.

Oh, I spent a lot of time trying to figure out what the difference was during synport. Even after staring at the code for a while I could only deduce that the distinction is maintained, but it didn't seem to have any visible effects

Yaël Dillies (Oct 18 2021 at 21:26):

Have a look at docs#zorn.chain for an example.

Floris van Doorn (Oct 18 2021 at 21:27):

However, the implementation of parameters is leaky, so sometimes this behavior doesn't work as this description says, and therefore parameter should generally not be used

Riccardo Brasca (Oct 18 2021 at 21:27):

Ah yes, it is even explained in TPL

Floris van Doorn (Oct 18 2021 at 21:28):

Mario Carneiro said:

Oh, I spent a lot of time trying to figure out what the difference was during synport. Even after staring at the code for a while I could only deduce that the distinction is maintained, but it didn't seem to have any visible effects

Haha, that's fair. It rarely has visible effects.

Yaël Dillies (Oct 18 2021 at 21:28):

I personally don't like parameter because when I look at the API code I have the assumption that this is how I'm going to use the lemmas. And then I always forget the arguments that were parametrized.

Yaël Dillies (Oct 18 2021 at 21:28):

I assume language models could get as confused as I am?

Mario Carneiro (Oct 18 2021 at 21:29):

universe variable / universe parameter was banished years ago, this distinction is entirely a relic of when "fixed universes" were a thing

Floris van Doorn (Oct 18 2021 at 21:30):

Until a couple minutes ago I thought that universes still had the behavior of universe parameters. My heuristic "don't use universe" is maybe outdated by a couple of years :)

Mario Carneiro (Oct 18 2021 at 21:31):

I think mathlib uses universe almost exclusively

Floris van Doorn (Oct 18 2021 at 21:33):

A quick search seems to suggest that it's used about 20x as much as universe variable.

Mario Carneiro (Oct 18 2021 at 21:33):

I find 33 uses of universe variable[s], 946 uses of universe[s], and 0 for universe parameter[s]

Mario Carneiro (Oct 18 2021 at 21:34):

and most of the uses of universe variable are from the old files like logic.basic, and some uses in witt vectors and category theory for some reason

Mario Carneiro (Oct 18 2021 at 21:37):

From a quick glance it looks like they are all at the top level, they aren't doing it to avoid undesired behavior in a section

Floris van Doorn (Oct 18 2021 at 21:37):

and at least one of which I added, in tests/simps :)

Mario Carneiro (Oct 18 2021 at 21:41):

#9794

Anne Baanen (Oct 19 2021 at 09:25):

Do we see any value in keeping the universes/section interaction, does it exist in Lean 4? If not, why don't we update Lean 3 so that universes always means universe variables (unless opted-in with universe parameters)?

Gabriel Ebner (Oct 19 2021 at 09:33):

We don't need universes at all in Lean 4.

Reid Barton (Oct 19 2021 at 12:50):

Oh wow, I knew about the universe/section interaction, but I never knew that universe variables meant something different--I thought it was just a verbose way of writing universes, and vaguely wondered why it was allowed or why anyone would write it.

Johan Commelin (Oct 19 2021 at 12:51):

I've been using universe variables ever since I heard that it was better behaved then universes in some corner cases. I never understood the details, so I just used it everywhere as a cargo cult plaster.

Reid Barton (Oct 19 2021 at 12:53):

Yaël Dillies said:

I personally don't like parameter because when I look at the API code I have the assumption that this is how I'm going to use the lemmas. And then I always forget the arguments that were parametrized.

parameter is for sections that prove a bunch of lemmas that build up to a main theorem, that could just as well be private (at least that's how I use it). It's an alternative organization strategy to writing single 500-line proofs.

Johan Commelin (Oct 19 2021 at 12:54):

I've used it in LTE once or twice, and it made the resulting file more readable, instead of less.

Yury G. Kudryashov (Oct 19 2021 at 18:10):

Do they exist in Lean 4?

Yury G. Kudryashov (Oct 19 2021 at 18:10):

I use a structure in branch#picard-lindelof

Kyle Miller (Oct 19 2021 at 19:07):

There's a sort of complicated feature that could be nice for reusing code: parameterized namespaces. If it existed, then it would give a different way to implement to_additive for example.

Here's an example of how it could work, in this case for adding some additional boilerplate that typeclasses can't add:

import data.set_like.basic

universes u v

namespace set_like_boilerplate
parameters (α : Type u  Type v) (X : Type u) [set_like (α X) X]

@[ext] lemma ext {p q : α X} (h :  (x : X), x  p  x  q) : p = q := set_like.ext h

end set_like_boilerplate


structure my_subobject (X : Type*) :=
(carrier : set X)

namespace my_subobject
variables (X : Type*)

instance : set_like (my_subobject X) X :=
my_subobject.carrier, λ p q h, by cases p; cases q; congr'

open set_like_boilerplate with my_subobject X

end my_subobject

I imagine it would create a namespace like normal (if namespace were like section and admitted parameters). But then in the open syntax there'd be an option to pass in parameters. Rather than including symbols, however, it would have to create new symbols. Adding to the complexity, there could be a way to give open a name rewrite function to be able to replace parts of symbol names (so for example, op to mul or add).

There are many many questions for how this would work. I've imagined that parameters was originally envisioned for some kind of parameterized modules, but the complexity was deferred, and it was realized that they're not essential.

Reid Barton (Oct 19 2021 at 19:36):

This is like ML modules I guess?

Kyle Miller (Oct 19 2021 at 20:06):

I think they're like ML functors in particular, but set up so that each declaration is still at the top level and can be typechecked individually like usual. It's also not aiming to do anything like having predefined signatures that the namespace is implementing -- that's what structure is for. This is trying to solve the problem "how do I specialize lemmas to have the correct syntax for rewriting, possibly giving the lemmas appropriate names?"


Last updated: Dec 20 2023 at 11:08 UTC