Zulip Chat Archive
Stream: new members
Topic: term mode partial function correctness proof?
Johannes C. Mayer (Nov 22 2021 at 18:00):
I am trying to do the exercise at the end of 7.2 in theorem proving in LEAN. I am a bit confused. How can you prove the second example in term mode?
namespace hidden
universe u
variables {α β γ : Type*}
inductive option (α : Type u) : Type u
| none : option
| some : α → option
def comp_partial (f : α → option β) (g : β → option γ) : α → option γ :=
λ ha, option.cases_on (f ha) option.none (λ hb, g hb)
variables (f : α → option β)
(g : β → option γ)
example (x : α) (h₁ : f x = option.none) :
((comp_partial f g) x) = option.none :=
begin
unfold comp_partial,
rewrite h₁,
end
-- How to do this in term mode?
example (x : α) (h₁ : f x = option.none) :
((comp_partial f g) x) = option.none :=
sorry
end hidden
Mario Carneiro (Nov 22 2021 at 18:04):
the short answer is that you shouldn't, tactic mode does this one better
Mario Carneiro (Nov 22 2021 at 18:08):
The long answer is
example (x : α) (h₁ : f x = option.none) : ((comp_partial f g) x) = option.none :=
@congr_arg _ (option γ) _ _ (λ y, option.cases_on y option.none g) h₁
Patrick Johnson (Nov 22 2021 at 18:11):
Use show_term
to see what the tactics compiled into:
begin
show_term {
unfold comp_partial,
rewrite h₁}
end
Johannes C. Mayer (Nov 22 2021 at 18:14):
@Patrick Johnson That does give me something, but it is extremely complicated, or at least pretty long. Right now I also don't get Mario's answer but that seems much easier to understand.
Mario Carneiro (Nov 22 2021 at 18:15):
The hard part in the proof is rw
, which makes for messy term proofs. I will usually use rw
even in a term mode proof because it's more reliable and about as fast
Mario Carneiro (Nov 22 2021 at 18:16):
The basic idea is that if you have some goal P x
containing a subterm x
and you want to replace it with y
given an equation h : x = y
, then use congr_arg P h
which has the type P x = P y
Mario Carneiro (Nov 22 2021 at 18:16):
the hard part is that you have to write down P
, where rw
will figure it out automatically by finding all instances of x
in the goal and replacing them with a lambda variable
Mario Carneiro (Nov 22 2021 at 18:18):
the other hard part in this particular problem is that option.cases_on
has a dependent type and this gives the elaborator trouble once it is removed from the context of comp_partial
where the type is known. This is why I had to specify the type option γ
to congr_arg
Mario Carneiro (Nov 22 2021 at 18:20):
The term used by rw
involves eq.rec
, which is very difficult to write manually unless you specify a bunch of implicit arguments because it has some unusual elaboration rules
Johannes C. Mayer (Nov 22 2021 at 18:24):
It also seems like even show_term
can't handle eq.rec
. I get: "invalid 'eq.rec' application, elaborator has special support for this kind of application (it is handled as an "eliminator"), but expected type must not contain metavariables", when I simply click on the 'try this' of show_term
.
Mario Carneiro (Nov 22 2021 at 18:29):
that's what I mean
Mario Carneiro (Nov 22 2021 at 18:30):
the lean 3 pretty printer has trouble round-tripping at the default printing settings when eq.rec
is involved
Mario Carneiro (Nov 22 2021 at 18:31):
you have to set_option pp.all true
or so, which will also make the output rather hard to read
Johannes C. Mayer (Nov 22 2021 at 18:41):
YES, that works. And also it makes the proof just hilariously long :joy: . 101 lines in fact.
Johannes C. Mayer (Nov 22 2021 at 19:13):
@Mario Carneiro I do get your proof now I think. It creates the term option.cases_on (f x) option.none g = option.none
right? And then LEAN looks at this and notices that it is definitionally equal to comp_partial f g x = option.none
.
Is there some way to make this last step more explicit? E.g. could we specify a rewrite operation to rewrite option.cases_on (f x) option.none g
to comp_partial f g x
?
Last updated: Dec 20 2023 at 11:08 UTC