Zulip Chat Archive
Stream: new members
Topic: Code smell?
Martin Dvořák (May 06 2022 at 21:48):
Is it a code smell if I often write apply congr_arg,
in my proofs?
Eric Wieser (May 06 2022 at 21:51):
Sometimes you might want congr' 1,
instead. refine congr_arg _ _
can also sometimes be more predictable
Martin Dvořák (May 07 2022 at 06:59):
Is it a code smell if I write change
immediately followed by convert_to
in some places (not many) of my proofs?
Damiano Testa (May 07 2022 at 07:07):
My experience with change
is that often you are better off proving a rfl
lemma doing the change for you. In some cases this simple trick has spectacular proof-shortening effects. I wish I had an example at hand, but I don't at the moment.
Martin Dvořák (May 07 2022 at 07:32):
You mean a lemma that "restates" the definition?
Damiano Testa (May 07 2022 at 08:17):
Yes, just a lemma whose proof is rfl
, guiding lean through the definition.
Martin Dvořák (May 07 2022 at 08:22):
Is there no better way how to tell Lean to apply / unapply definition without creating this boilerplate? Unfortunately unfold
does not always do what I want.
Eric Wieser (May 07 2022 at 08:27):
Can you give an example of a definition where unfold
does the wrong thing?
Martin Dvořák (May 07 2022 at 08:28):
Yes, I can. However, making MWE out of it will probably be hard.
Eric Wieser (May 07 2022 at 08:29):
What's the non-mwe version? Can you link to a gist or something?
Martin Dvořák (May 07 2022 at 08:33):
I am unpacking this definition:
https://github.com/madvorak/grammars/blob/75c5d5db4be45957bafd1d651086821af4373472/src/context_free/cfg.lean#L29
Unfotunately unfold CF_generates,
does not work.
Martin Dvořák (May 07 2022 at 08:35):
It gives me: simplify tactic failed to simplify
Eric Wieser (May 07 2022 at 08:46):
What's the goal state at that point
Martin Dvořák (May 07 2022 at 08:48):
I would like to obtain CF_generates_str (union_grammar g₁ g₂) (list.map symbol.terminal w),
without stating it explicitly. My change
only does what I supposed that unfold
would do.
Kevin Buzzard (May 07 2022 at 08:51):
I would say that unfold
is a code smell indicating that there is missing boilerplate.
Martin Dvořák (May 07 2022 at 08:52):
Is there really no better way than repeating the definition again as a lemma? I hate how it looks.
Yaël Dillies (May 07 2022 at 09:09):
Does rw CF_generates
do what you want?
Martin Dvořák (May 07 2022 at 09:11):
It gives me: failed
Eric Wieser (May 07 2022 at 09:15):
Martin Dvořák said:
I would like to obtain
CF_generates_str (union_grammar g₁ g₂) (list.map symbol.terminal w),
without stating it explicitly. Mychange
only does what I supposed thatunfold
would do.
Yes, but what was the goal state before that?
Martin Dvořák (May 07 2022 at 09:17):
Oh sorry. It was: w ∈ CF_generates (union_grammar g₁ g₂)
Eric Wieser (May 07 2022 at 09:18):
That goal is nonsense
Eric Wieser (May 07 2022 at 09:18):
CF_generates
isn't a set
Eric Wieser (May 07 2022 at 09:18):
How did you get there?
Eric Wieser (May 07 2022 at 09:19):
Is language
docs#language?
Eric Wieser (May 07 2022 at 09:19):
If so, these lines are wrong
https://github.com/madvorak/grammars/blob/75c5d5db4be45957bafd1d651086821af4373472/src/context_free/cfg.lean#L33-L34
Eric Wieser (May 07 2022 at 09:19):
That should be
def CF_language : language T :=
set_of (CF_generates g)
Martin Dvořák (May 07 2022 at 09:23):
Oh, thanks a lot!!
So I cannot use set t
as t → Prop
hoping that it is definitionally equivalent?
Eric Wieser (May 07 2022 at 09:23):
You'll find you have to fight with change
all the time if you do that
Martin Dvořák (May 07 2022 at 09:24):
Thank you very much!!! This change will eliminate change
in so many places!!!
Eric Wieser (May 07 2022 at 09:24):
They're definitionally equivalent, but to keep things in a state where lean will help you, you use ∈
to convert a set into a function, and docs#set_of (aka {x | p x}
) to convert a function into a set
Martin Dvořák (May 07 2022 at 09:28):
I don't know whether it is related but... When I have a goal in the form of list.mem a L
existing lemmata about lists don't work. I have to change
it to a ∈ L
and only then they can be applied. Is there a similar trick for that?
Yaël Dillies (May 07 2022 at 09:34):
Same question. How did you get there?
Martin Dvořák (May 07 2022 at 09:42):
I had: r_in : r ∈ (head :: tail)
https://github.com/madvorak/grammars/blob/75c5d5db4be45957bafd1d651086821af4373472/src/context_free/closure_properties/binary/CF_union_CF.lean#L151
I called: cases r_in,
The first case was great: r = head
The second case was: list.mem r tail
What could I have done instead to obtain r ∈ tail
please?
Eric Wieser (May 07 2022 at 09:48):
You should have looked for a lemma that matches the form of the hypothesis
Eric Wieser (May 07 2022 at 09:48):
#naming suggests it would be called docs#list.mem_cons
Eric Wieser (May 07 2022 at 09:49):
Clicking that link reveals it's called docs#list.mem_cons_iff
Eric Wieser (May 07 2022 at 09:49):
Either way, if you type list.mem_cons
in vs-code, autocomplete should do the rest
Martin Dvořák (May 07 2022 at 09:49):
Thanks a lot!!!
Martin Dvořák (May 07 2022 at 09:50):
Is there a general methodical mistake that I make?
Eric Wieser (May 07 2022 at 09:50):
In fact, cases list.eq_or_mem_of_mem_cons r_in
is probably what you want, where that lemma is just below the one I linked to
Eric Wieser (May 07 2022 at 09:50):
Martin Dvořák said:
Is there a general methodical mistake that I make?
Always search for a lemma before unfolding. To some extent, cases
does unfolding too. Use your judgement on the output of cases
to decide if you might have unfolded too far
Eric Wieser (May 07 2022 at 09:51):
An easy way to search for useful lemmas is just simp?
Martin Dvořák (May 07 2022 at 09:51):
I learnt to use squeeze_simp
only recently.
Eric Wieser (May 07 2022 at 09:51):
Which might not get you to where you want to be, but will usually take you to a place where it's easier to find matching lemmas
Eric Wieser (May 07 2022 at 09:51):
Martin Dvořák said:
I learnt to use
squeeze_simp
only recently.
That's better than simp?
but a bit slower
Martin Dvořák (May 07 2022 at 13:53):
Is it a code smell when I have the following pair of lines in my code?
rw some_lemma,
rw some_lemma at some_assumption,
Rémy Degenne (May 07 2022 at 13:55):
You can write instead the shorter
rw some_lemma at some_assumption ⊢,
That last sign means the goal.
Rémy Degenne (May 07 2022 at 13:57):
Writing such a line is not uncommon and not a code smell in itself
Martin Dvořák (Jun 01 2022 at 09:06):
Is it idiomatic to use variable
instead of variables
when adding a single (implicit) argument?
Yaël Dillies (Jun 01 2022 at 09:09):
I tend not to because my brain always bugs when I then add another variable to it and get a weird error.
Eric Wieser (Jun 01 2022 at 09:10):
Yeah, I agree; the very marginal readability benefit is totally outweighed by the awkwardness to edit
Eric Wieser (Jun 01 2022 at 09:11):
It would be like having [1, 2, and 3]
as list notation
Martin Dvořák (Jun 01 2022 at 09:13):
It smells like a slightly bad design decision that both variable
and variables
exist.
Yaël Dillies (Jun 01 2022 at 09:15):
I think it would be fine if they were functionally the same.
Martin Dvořák (Jun 01 2022 at 09:15):
However, I am pretty fine with both intro
and intros
because I almost never edit them.
Mario Carneiro (Jun 01 2022 at 09:19):
Note that in lean 4 variable
has been deleted and variables
has been renamed to variable
Mario Carneiro (Jun 01 2022 at 09:20):
I think intro
is just as bad TBH. rintro
is just silently identical to rintros
Yaël Dillies (Jun 01 2022 at 09:21):
Yeah, I always use rintro
instead of intro
and intros
for the same reasons.
Mario Carneiro (Jun 01 2022 at 09:22):
Plurals were a mistake :trademark:
Mario Carneiro (Jun 01 2022 at 09:25):
Although, a variation on this same "one looks different from more than one" issue is rw e
vs rw [e1, e2]
Mario Carneiro (Jun 01 2022 at 09:25):
lean 4 also removed the first version, possibly for this reason
Martin Dvořák (Jun 01 2022 at 09:27):
I really like rw e
as it works in lean 3.
Martin Dvořák (Jun 01 2022 at 09:41):
BTW, is it a bad style if I declare variables
which are then used only in small portion of the stuff in the given scope?
Patrick Massot (Jun 01 2022 at 09:41):
We do it all the time in mathlib
Martin Dvořák (Jun 01 2022 at 09:43):
Is it OK even if they occupy "expensive" identifiers (i.e., one-letter names)?
Eric Wieser (Jun 01 2022 at 09:51):
You can always "shadow" expensive variable names in lemma
statements
Eric Wieser (Jun 01 2022 at 09:52):
The two main problems you face when having too many variables are usually:
- Having a type
R
that has too many typeclasses in thevariables
list, and not being able to easily exclude those without declaring a brand newR
- Not remembering whether the
variables
line 100 lines up the file uses()
or{}
to declare the variables, and getting your argument implicitness wrong as a result
Martin Dvořák (Jun 02 2022 at 19:01):
Am I the only one who finds it confusing to use variables
for explicit arguments (a : T)
shared by multiple items? I have a natural tendency to expect, when I look at a declaration of a function, to see all arguments that I need to pass when calling the function.
The code intellisense "quick info" in VSCode shows all arguments (including those written using variables
anywhere above) but I like to look at my definition in the code. There I easily get confused by an "invisible" required argument.
Violeta Hernández (Jun 02 2022 at 19:02):
I agree that it's confusing. Gets particularly annoying when you add a few extra theorems and suddenly the argument a
can be made implicit in them
Martin Dvořák (Jun 02 2022 at 19:04):
So, should I use variables
only for {stuff}
and [stuff]
for the sake of code readability?
Violeta Hernández (Jun 02 2022 at 19:05):
I mean, if you have 15 theorems in a code block and all of them need an explicit argument, I'd say using variables (stuff)
is fine
Violeta Hernández (Jun 02 2022 at 19:06):
But if it's just a handful, then it's not a great idea
Martin Dvořák (Jun 02 2022 at 19:14):
I'd like to hear more opinions about this issue. It has been bugging me recently a lot.
Yaël Dillies (Jun 02 2022 at 19:18):
I have the same stance as Violeta. Unless all your lemmas are gonna need the same explicit arguments, restrict variables
declarations to implicit or instance arguments.
Martin Dvořák (Jun 02 2022 at 19:19):
And if they do, does it justify the loss of readability?
Violeta Hernández (Jun 02 2022 at 19:20):
I think that in some cases, you gain a lot of readability. Writing down (a : T) (b : U) (c : V)
over and over, particularly when the types have much longer names, and particularly when they're clear from context, is quite a chore
Eric Wieser (Jun 02 2022 at 19:27):
I think my view lies closer to Martin's here. One other case to consider; if one of your explicit arguments is a Type
, it's a chore to repeat all its typeclasses on a lemma. Usually this is handled with variables (R)
the_lemma
variables {R}
Eric Wieser (Jun 02 2022 at 19:27):
Which is still fairly readable because the explicit argument is adjacent
Martin Dvořák (Jun 03 2022 at 16:43):
Is there a shortcut for the following two lines?
rw set.mem_set_of_eq at ⊢ h,
rw set.mem_set_of_eq at ⊢,
I want to apply set.mem_set_of_eq
twice to the goal and once to h
.
Riccardo Brasca (Jun 03 2022 at 16:45):
Does
simp only [set.mem_set_of_eq] at ⊢ h
work?
Yaël Dillies (Jun 03 2022 at 16:47):
dsimp at ⊢ h,
?
Damiano Testa (Jun 03 2022 at 16:48):
Or even not doing anything? :upside_down:
Riccardo Brasca (Jun 03 2022 at 16:49):
Ah yes, I didn't even had a look of what the lemma was.
To clarify, the lemma is useful for a human being, but the LHS is defined to be the RHS, so it's possible the Lean doesn't need it at all.
Martin Dvořák (Jun 03 2022 at 17:00):
Riccardo Brasca said:
Does
simp only [set.mem_set_of_eq] at ⊢ h
work?
Yes, it does. However, I don't like calling simp
for something that I know precisely how to do.
Martin Dvořák (Jun 03 2022 at 17:05):
I tried rw set.mem_set_of_eq at ⊢ h ⊢,
but was disappointed.
Martin Dvořák (Jun 03 2022 at 17:06):
I don't mind that much that I have to write two nearly-identical lines. I hate that the "three operations" are grouped into "two commands" in a counter-intuitive way.
Damiano Testa (Jun 03 2022 at 17:09):
Maybe you could try repeat { rw set.mem_set_of_eq, try { rw set.mem_set_of_eq at h } }
?
Damiano Testa (Jun 03 2022 at 17:09):
I'm not sure what we are aiming for here, though...
Martin Dvořák (Jun 03 2022 at 17:13):
Damiano Testa said:
I'm not sure what we are aiming for here, though...
I am aiming for something less awkward. If it cannot be done, I will put up with it.
Martin Dvořák (Jun 03 2022 at 17:13):
Damiano Testa said:
Maybe you could try
repeat { rw set.mem_set_of_eq, try { rw set.mem_set_of_eq at h } }
?
I'd rather write three lines than this.
Damiano Testa (Jun 03 2022 at 17:14):
But have you tried just skipping the rw?
Damiano Testa (Jun 03 2022 at 17:14):
What is the next line in your proof?
Martin Dvořák (Jun 03 2022 at 17:18):
I know I can skip this rw
. However, according to some advice I obtained here previously, I decided to define stuff with set_of
in order to avoid the command change
. So now, I want to take advantage of that. I am aware that set.mem_set_of_eq
does only a definitional equality; however, it has impact on the effect of some other tactics. And I don't feel like going to change
again.
Kyle Miller (Jun 03 2022 at 17:18):
Martin Dvořák said:
Yes, it does. However, I don't like calling
simp
for something that I know precisely how to do.
I'm curious what the motivation is for this preference -- simp
is designed for repeatedly doing rewrites like this.
But if this preference is strong, you can refactor it as
repeat { rw set.mem_set_of_eq },
rw set.mem_set_of_eq at h,
Martin Dvořák (Jun 03 2022 at 17:25):
Calling simp
performs some kind of state-space search. Why would I tell the computer to perform the search every time it rebuilds my project if I can explicitly say what three substitutions lead to the desired state?
Martin Dvořák (Jun 03 2022 at 17:27):
BTW, I don't like calling repeat
for something that I want to do exactly twice. What is your preference?
Damiano Testa (Jun 03 2022 at 17:28):
Regarding your state-space search, it would be interesting to measure the time difference. After all, rw
also looks around the expression to find locations to perform the rewrite. I wonder which one is faster. It might depend on the expression itself...
Damiano Testa (Jun 03 2022 at 17:30):
I have certainly observed simp
producing shorter proof terms than the corresponding chain of rewrites, but not always.
Martin Dvořák (Jun 03 2022 at 17:31):
I like to use simp
together with have
or convert
but not in the middle of my proof.
Martin Dvořák (Jun 03 2022 at 17:32):
I know that simp only
is pretty safe to use, but I still don't like it in non-terminal positions.
Damiano Testa (Jun 03 2022 at 17:32):
I'm also wary of non-terminal simps, so I understand your concern.
Martin Dvořák (Jun 03 2022 at 17:34):
In general, I prefer to use simp
less often. Also my friends make fun of me: "Look, Martin is simping for math again!"
Kyle Miller (Jun 03 2022 at 17:36):
Martin Dvořák said:
Calling
simp
performs some kind of state-space search.
How much work do you think it's doing here? It might be called "simp" but that doesn't mean it's looking for the simplest representation (unless the simp
lemmas you provide cause it to enter rewrite cycles, like with add_assoc
and add_comm
together)
Yakov Pechersky (Jun 03 2022 at 17:37):
simp only is not calling any lemmas other than the ones you provide. It still does things that rw doesn't, like beta reduction
Kyle Miller (Jun 03 2022 at 17:37):
If you don't like repeat
, then try tactic#iterate or
rw [set.mem_set_of_eq, set.mem_set_of_eq],
rw set.mem_set_of_eq at h,
Stuart Presnell (Jun 03 2022 at 19:45):
If you’re doing something to be PRed to mathlib then the preference is (other things being equal) for shorter solutions. So if simp only
does the job, your personal preference for a more verbose spelling likely won’t make it through review. Of course, this isn’t an issue if you’re just writing for your own projects.
Martin Dvořák (Jun 03 2022 at 20:09):
Yes, it is a project that only I write.
Martin Dvořák (Jun 05 2022 at 07:35):
Is there a more idiomatic way how to write clear_except,
to delete everything but the goal?
Martin Dvořák (Jun 21 2022 at 15:40):
Is there a shortcut for the following construction?
have sublemma : ∃ x, (...),
{
(...)
},
cases sublemma with x hx,
I repeat lines like the above very often.
Julian Berman (Jun 21 2022 at 15:44):
I think obtain
is meant to be the shortcut for have
+ cases
-- i.e. obtain \<x, hx\> := stuffinyourproof
, with or without the explicit type if necessary
Eric Rodriguez (Jun 21 2022 at 15:45):
I can't remember whether obtain
suuports the ,
syntax instead of := { ... }
specifically, but otherwise yes
Mario Carneiro (Jun 21 2022 at 15:53):
it does
Mario Carneiro (Jun 21 2022 at 15:53):
you have to give the type if you want to pattern match though, obtain \<x, y\>,
doesn't work
Bart Michels (Jun 21 2022 at 17:53):
Mario Carneiro said:
you have to give the type if you want to pattern match though,
obtain \<x, y\>,
doesn't work
I assume that's because the notation is ambiguous when you have nested constructors?
Bart Michels (Jun 21 2022 at 17:57):
Like if you want to obtain \<x, y, z\>
of type (p \and q) \and (r \and s)
.
Mario Carneiro (Jun 21 2022 at 18:05):
No, it's always right associative in that sense. It's because it is ambiguous what we are destructing: it could be Exists.rec
or and.rec
or nat.rec
Mario Carneiro (Jun 21 2022 at 18:06):
you can't pattern match on something of unknown type: obtain <x, y> := _
is an error
Bart Michels (Jun 21 2022 at 18:24):
I'm not sure if I don't get it or if I am thinking the same. Say I have
something of type (∃ n : ℕ, p n) ∧ (∃ n : ℕ, q n)
. How is this different from ((p ∧ q) ∧ r) ∧ ((s ∧ t) ∧ u)
(except for the fact that the n
s can be further destructed) ?
Mario Carneiro (Jun 21 2022 at 18:24):
you can't use exists.rec
to destruct an element of the second type
Bart Michels (Jun 21 2022 at 18:24):
I mean, I agree that it's ambiguous, I am just surprised that you (seem to) say that it's not for something like (p ∧ q) ∧ (s ∧ t)
Mario Carneiro (Jun 21 2022 at 18:25):
the tactic has to decide what theorem to apply, and it needs the type to do that
Mario Carneiro (Jun 21 2022 at 18:25):
the brackets can be nested in different ways if you want to destruct stuff like (p ∧ q) ∧ (s ∧ t)
Mario Carneiro (Jun 21 2022 at 18:26):
you would need to use <<hp, hq>, <hs, ht>>
to match that
Mario Carneiro (Jun 21 2022 at 18:26):
obtain doesn't try to be smart about associativity if you don't write the brackets correctly
Mario Carneiro (Jun 21 2022 at 18:27):
you can also use <<hp, hq>, hs, ht>
in that case but that's just because the angle brackets are always interpreted as right associative
Mario Carneiro (Jun 21 2022 at 18:27):
<hp, hq, <hs, ht>>
would not work
Bart Michels (Jun 21 2022 at 18:31):
But then I don't see why lean wouldn't know what to destruct. Can it not just look at the top-most symbol?
Bart Michels (Jun 21 2022 at 18:31):
When you say "It's because it is ambiguous what we are destructing:"
Mario Carneiro (Jun 21 2022 at 18:33):
because the top most symbol is ?m_1
Mario Carneiro (Jun 21 2022 at 18:33):
if the type is not known
Mario Carneiro (Jun 21 2022 at 18:34):
if you write obtain <x, y>,
with literally no other information, how can it tell what you want to destruct?
Mario Carneiro (Jun 21 2022 at 18:35):
you can use obtain <x, y> : \exists n, P n,
or obtain <x, y> := h
, both of which provide a way to get the type
Bart Michels (Jun 21 2022 at 18:35):
Right, thanks. I was assuming that lean would derive the type from the {}
block that follows.
Mario Carneiro (Jun 21 2022 at 18:36):
it can't use types from the future because after the ,
the tactic runs and it has to transition the tactic state to something such that the {}
block will do something useful
Bart Michels (Jun 21 2022 at 18:37):
Got it, makes a lot of sense.
Bart Michels (Jun 21 2022 at 18:37):
Thanks!
Martin Dvořák (Jul 26 2022 at 14:29):
Martin Dvořák said:
Is there a more idiomatic way how to write
clear_except,
to delete everything but the goal?
I encountered it again. Is there any idiomatic way to write it? I kinda wanna signpost that I will show that the goal is tautological.
Martin Dvořák (Aug 30 2022 at 09:29):
What should I do instead of the following two lines?
have my_inequality_ := my_inequality,
tauto,
I want to "load" an existing private lemma into a local context in order to discharge the goal by tauto
with its help?
Alex J. Best (Aug 30 2022 at 11:12):
Seems fine to me
Martin Dvořák (Aug 30 2022 at 11:50):
I'd rather do something like tauto [my_inequality]
or perform tauto
with library_search
at the same time.
Or, is there a way to do what I did without needing to name the proposition again?
Ruben Van de Velde (Aug 30 2022 at 11:51):
You can use have := xxx
which will call the local assumption this
Martin Dvořák (Aug 30 2022 at 11:55):
Is it idiomatic in Lean? I guess it is OK when I write have := my_inequality,
on the penultimate line of the block (followed by a tactic that does not obtain this
as an explicit argument).
Alex J. Best (Aug 30 2022 at 13:24):
Using this
is fairly idiomatic, and some tactics like simpa using
have special support for it even
Martin Dvořák (Sep 23 2022 at 11:38):
In my proofs, my block often ends with something like:
have almost_there := some_lemma some_parameter,
rw [some_transformation, other_transformation] at almost_there,
exact almost_there,
Is there a better way to write it?
Eric Rodriguez (Sep 23 2022 at 11:39):
rwa
:)
Martin Dvořák (Sep 23 2022 at 11:40):
The line have almost_there := some_lemma some_parameter,
has to stay, I guess.
Yaël Dillies (Sep 23 2022 at 11:41):
simpa only [some_transformation, other_transformation] using some_lemma some_parameter
might or might not work in your situation.
Yaël Dillies (Sep 23 2022 at 11:41):
Is there any reason rwa [] using _
is not supported syntax?
Martin Dvořák (Sep 23 2022 at 11:45):
Eric Rodriguez said:
rwa
:)
Isn't it a bit slower? I'd rather have it call exact
[right side of rwa
] than to walk through the local context.
Yaël Dillies (Sep 23 2022 at 11:52):
It's almost no difference, given that you will typically have less < 50 assumptions in context. And note that this is also (slightly) cheaper in tactic parsing.
Eric Rodriguez (Sep 23 2022 at 12:10):
Yaël Dillies said:
Is there any reason
rwa [] using _
is not supported syntax?
Ooh this would be really nice
Martin Dvořák (Oct 18 2022 at 12:17):
Is it bad practice to reuse argument names between different functions / lemmata and have x
of different type in different parts of your code?
Johan Commelin (Oct 18 2022 at 12:19):
Not necessarily. But having multiple x
s` at the same time will be confusing.
Martin Dvořák (Nov 02 2022 at 15:09):
What about dsimp only [],
in the middle of a proof?
Kyle Miller (Nov 02 2022 at 15:11):
Those are fine according to mathlib standards.
A small golf: dsimp only
does the same thing as dsimp only []
Kyle Miller (Nov 02 2022 at 15:13):
One of the reasons dsimp only
appears is that it's able to do a number of reductions that are necessary for further rewrites.
Kyle Miller (Nov 02 2022 at 15:14):
Even dsimp
is allowed, because theoretically it transforms something into something definitionally equivalent, so it's not so bad fixing things if the simp set changes. (I usually still go for dsimp only [whatever the lemmas]
when possible)
Kyle Miller (Nov 02 2022 at 15:15):
But, once you're done with a proof, it's worth checking if there are any dsimp
s (or unfold
s) that you can remove. It can be surprising what's not necessary.
Martin Dvořák (Nov 02 2022 at 15:16):
I usually realize that dsimp
and unfold
cannot be removed.
Martin Dvořák (Nov 17 2022 at 12:36):
Is there a way how to replace the following two lines by a single command?
have is_it_in := congr_arg (λ l, 42 ∈ l) hyp,
dsimp only at is_it_in,
I wish there was a way to write the congr_arg
expression in a way that will not require the beta reduction immediately after it.
Ruben Van de Velde (Nov 17 2022 at 12:41):
You could use have is_it_in : 42 \in a = 42 \in b := congr_arg ..
(if I remembered congr_arg
correctly)
Martin Dvořák (Nov 17 2022 at 12:47):
That's a bit too verbose but thanks.
Ruben Van de Velde (Nov 17 2022 at 12:50):
Oh, or maybe even have is_it_in : _ \in _ = _ \in _ := ...
Alex J. Best (Nov 17 2022 at 12:53):
You could use tactic#dsimp_result, for this example its still a bit verbose but it might be helpful in other cases
import data.set.basic
example (a b : set ℕ) (hyp : a = b) : false :=
begin
have is_it_in, { dsimp_result { exact congr_arg (λ l, 42 ∈ l) hyp} },
end
Kyle Miller (Nov 17 2022 at 12:57):
Ext lemmas are good for these too
example (α : Type*) (s t : set α) (h : s = t) (x : α) : x ∈ s ↔ x ∈ t :=
begin
have := set.ext_iff.mp h x,
exact this
end
Kyle Miller (Nov 17 2022 at 12:57):
For submodules you can for example use docs#set_like.ext_iff since they tend to use the set_like
interface
Martin Dvořák (Nov 25 2022 at 10:58):
I have the following block, which totally looks like a code smell, on six places in my code.
exfalso,
(...)
apply false_of_true_eq_false,
convert my_hyp.symm,
{
rw [eq_iff_iff, true_iff],
(...)
},
{
rw [eq_iff_iff, false_iff],
(...)
}
Is there a better way to write the same thing without significantly changing the decomposition?
Anne Baanen (Nov 25 2022 at 11:19):
If I read this right, the situation is that my_hyp : p = q
, and you have a proof of p
and a proof of ¬ q
? I'd probably structure this as:
have : ¬ q :=
{ ... },
refine (this _).elim,
rw my_hyp,
-- Now prove `p`
{ ... }
Anne Baanen (Nov 25 2022 at 11:20):
Another option might be:
have hp : p,
{ ... },
have hnq : ¬ p,
{ rw my_hyp,
-- Now prove `¬ q`
... },
contradiction
Martin Dvořák (Nov 25 2022 at 11:24):
Oh yes, thanks!
Is there also a way that doesn't require me to restate p
and/or q
?
Martin Dvořák (Nov 25 2022 at 11:26):
Motivation: I often work with propositions that take more than 100 characters to state. And I don't like boilerplate in my code.
Anne Baanen (Nov 25 2022 at 11:39):
The best I can figure out is the rather cryptic (mt (eq.mp my_hyp) _ _).elim
Anne Baanen (Nov 25 2022 at 11:40):
Or I guess absurd (eq.mp my_hyp _) _
?
Reid Barton (Nov 25 2022 at 19:42):
Martin Dvořák said:
Motivation: I often work with propositions that take more than 100 characters to state
Some people would claim that this is the code smell
Junyan Xu (Nov 26 2022 at 03:11):
A bit late but this directly gives what you wanted:
import data.set.basic
example (a b : set ℕ) (hyp : a = b) : false :=
begin
have := congr_arg ((∈) 42) hyp, /- this: 42 ∈ a = (42 ∈ b) -/
end
Last updated: Dec 20 2023 at 11:08 UTC