Zulip Chat Archive

Stream: general

Topic: Using structure fields as they're defined


Eric Wieser (Nov 10 2020 at 18:31):

Is it possible to do something like this?

example : my_structure :=
{ f := sorry,
  prop_a := sorry,
  prop_b := begin
     rw some_stuff,
     rw prop_a, -- I want to reuse my proof of a
     sorry
  end }

Obviously right now prop_a doesn't resolve. Currently, my options look to be:

  • Use a private definition to provide my definition of f and proof ofprop_a first, and then put it in the struct later
  • Do something horrible with let in

Johan Commelin (Nov 10 2020 at 18:33):

I guess that lean doesn't want to be bothered with figuring out whether proofs refer to each other in a cyclic manner...

Eric Wieser (Nov 10 2020 at 18:33):

I'd be happy with it requiring source order

Reid Barton (Nov 10 2020 at 18:33):

I don't think that really makes sense unfortunately.

Eric Wieser (Nov 10 2020 at 18:33):

Or in most cases, probably even struct field order

Reid Barton (Nov 10 2020 at 18:34):

Like, what term do you expect it to produce

Reid Barton (Nov 10 2020 at 18:34):

It has to produce something you could write by hand anyways

Eric Wieser (Nov 10 2020 at 18:35):

I guess I'd want it to just inline the term it already produced

Eric Wieser (Nov 10 2020 at 18:40):

Is using private the right thing to do here?

Johan Commelin (Nov 10 2020 at 18:40):

I think I would go for that option, yes.

Johan Commelin (Nov 10 2020 at 18:41):

The let in is not really horrible, but I understand why you call it horrible :rolling_eyes: :rofl: :oops: :shrug:

Reid Barton (Nov 10 2020 at 18:41):

Another possibility is

example : my_structure :=
begin
  refine { f := [...], .. },
  all_goals { have prop_a : [...] := [...] },
  { exact prop_a },
  { rw [some_stuff, prop_a], [...] }
end

Reid Barton (Nov 10 2020 at 18:42):

let in is bad, but I think have is less bad, so that's another possible option

Alex J. Best (Nov 10 2020 at 18:42):

I guess the have is weird if the f is something complicated that appears in the type of prop_a

structure my_structure :=
(f :   )
(prop_a : f 0 = 0)
(prop_b : f 0 + 0 = 0)
example : my_structure := have prop_a : id 0 = 0 := rfl,
{ f := id,
  prop_a := prop_a,
  prop_b := begin
     rw prop_a, -- I want to reuse my proof of a
  end }

Reid Barton (Nov 10 2020 at 18:44):

The have is still probably worse than just writing a separate lemma

Eric Wieser (Nov 10 2020 at 18:44):

Do private lemmas appear in the online docs?

Kevin Lacker (Nov 10 2020 at 18:45):

if you name it like blah_blah_aux then people will know not to use it

Eric Wieser (Nov 10 2020 at 18:46):

Right, but my hope was the private keyword would do something sensible

Reid Barton (Nov 10 2020 at 18:46):

Normally private is not recommended but if it's literally a field of a structure that you provide anyways, I guess it's okay

Kevin Lacker (Nov 10 2020 at 18:47):

o rly. why isn't private recommended?

Johan Commelin (Nov 10 2020 at 18:47):

Because 95% of the time, it turns out that someone else has a use for your lemma

Johan Commelin (Nov 10 2020 at 18:47):

So they will be happy if they can use it outside the file where it's defined.

Kevin Lacker (Nov 10 2020 at 18:51):

seems strange to me based on the analogy to other programming, but I guess there is basically never a reason to refactor a lean lemma to "change its behavior", because it has no behavior, so there isn't really any need to say like, don't depend on this because its behavior may change

Gabriel Ebner (Nov 10 2020 at 18:52):

It's not impossible, but you'll need to modify the C++ code for this.

Reid Barton (Nov 10 2020 at 18:55):

Kevin Lacker said:

seems strange to me based on the analogy to other programming

I agree there could theoretically be a world in which a module has a public API which is stable and an implementation which is not, but mathlib is nowhere near that point and it seems difficult in practice because Lean really likes to unfold definitions.

Johan Commelin (Nov 10 2020 at 18:56):

I've recently marked some things private that were used in setting up a bundled homomorphism. In that case, I think it's justified, because everything this scaffolding achieves can be done using the API of bundled morphisms as well, once the bundled hom is available.

Eric Wieser (Nov 10 2020 at 19:01):

Right, the use case you describe is exactly mine - all the lemmas are going to end up bundled in a larger structure, exposing them under two different names is just confusing

Mario Carneiro (Nov 10 2020 at 19:27):

I would recommend something like this:

structure my_structure :=
(f :   )
(prop_a : f 0 = 0)
(prop_b : f 0 + 0 = 0)
example : my_structure :=
let f :    := id in
have prop_a : f 0 = 0 := rfl,
{ f := f,
  prop_a := prop_a,
  prop_b := begin
     rw prop_a, -- I want to reuse my proof of a
  end }

Mario Carneiro (Nov 10 2020 at 19:31):

Kevin Lacker said:

o rly. why isn't private recommended?

Johan Commelin said:

Because 95% of the time, it turns out that someone else has a use for your lemma

Exhibit A, where Kevin Lacker uses a "private" lemma from norm_num

Mario Carneiro (Nov 10 2020 at 19:34):

Kevin Lacker said:

seems strange to me based on the analogy to other programming, but I guess there is basically never a reason to refactor a lean lemma to "change its behavior", because it has no behavior, so there isn't really any need to say like, don't depend on this because its behavior may change

Actually this is a thing. Definitions do change their behavior, either when the definition changes to something defeq, or something which is equal but not defeq, or something which is really different but only differs in "out of bounds" areas that most theorems don't care about, or type of an intermediate definition changes and the API layer needs to be reworked but theorems above that don't have to change.

Mario Carneiro (Nov 10 2020 at 19:35):

We usually call it "refactoring"

Kevin Lacker (Nov 10 2020 at 21:12):

Mario Carneiro said:

Kevin Lacker said:

o rly. why isn't private recommended?

Johan Commelin said:

Because 95% of the time, it turns out that someone else has a use for your lemma

Exhibit A, where Kevin Lacker uses a "private" lemma from norm_num

hey, i didn't want to use a private lemma from norm_num, some reviewer suggested it because it made the code 1 token shorter

Junyan Xu (Oct 05 2021 at 04:00):

Aren't structures implemented as sigma types? The fields should have a linear order on them so no cyclic reference is possible. In fact, when defining the type of a structure it is allowed to use previously defined fields, and it's odd to me that you can't do so when exhibiting a term of the type.

Mario Carneiro (Oct 05 2021 at 04:11):

It's not clear to me what you are responding to or what you mean. Do you have an example? Structures are just an extension of sigma types, cyclic reference is impossible, and fields can have types that refer to previous fields

Junyan Xu (Oct 05 2021 at 04:13):

This was the "cyclic" concern:
Johan Commelin said:

I guess that lean doesn't want to be bothered with figuring out whether proofs refer to each other in a cyclic manner...

Junyan Xu (Oct 05 2021 at 04:13):

I'm just complaining as I find it inconvenient.

Junyan Xu (Oct 05 2021 at 04:15):

The specific situation is that I want to use fac' when proving uniq' in is_limit: https://leanprover-community.github.io/mathlib_docs/category_theory/limits/is_limit.html#category_theory.limits.is_limit

Scott Morrison (Oct 05 2021 at 04:15):

Just write a preliminary lemma with the fact you want to use twice. (Or a let X := Y in ... statement.)

Junyan Xu (Oct 05 2021 at 04:17):

when proving fac' I can just intro/lambda without specifying the types, but when writing a lemma I have to write the types, and can't just write the term. Just seems unnecessarily verbose to me.

Scott Morrison (Oct 05 2021 at 04:20):

Have you seen tactic#extract_goal?

Junyan Xu (Oct 05 2021 at 04:24):

I've seen that but my issue isn't with difficulty writing down the lemma but the space the lemma would occupy. My reaction to inability to refer to the prior field is not to replicate the proof or extract a lemma, but to find an alternative proof. I've tried tactic#abstract before but nothing happened. Maybe time to give it a try again.
(Maybe nothing appears in the local context but I can use it as a global definition/theorem?)

Mario Carneiro (Oct 05 2021 at 04:27):

There is a straightforward syntactic modification that will make the proof available later. You don't have to write the type

Junyan Xu (Oct 05 2021 at 06:57):

Mario Carneiro said:

There is a straightforward syntactic modification that will make the proof available later. You don't have to write the type

Not sure if this the way you're talking about, but I managed to make tactic#abstract work! If the theorem you're proving is named foo, you can abstract goal { /- proof of goal -/ } in tactic mode to extract the first goal to a lemma, and then you can refer to the lemma using foo.goal either within the same proof, or later in the same file. The prefix foo. is what I was missing, and isn't mentioned in the documentation.

Mario Carneiro (Oct 05 2021 at 23:18):

I was talking about using let, but that works too


Last updated: Dec 20 2023 at 11:08 UTC