Zulip Chat Archive
Stream: lean4
Topic: when does a branch in the first combinator change the goal?
Bulhwi Cha (Apr 03 2025 at 13:00):
Consider the following example from Section Tactic Combinators of #tpil:
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
repeat (first | apply Or.inl; assumption | apply Or.inr | assumption)
The compound tactic first tries to solve the left disjunct, p
, immediately by assumption. That attempt fails, and the goal remains the same. It then tries to focus on the right disjunct, q ∨ r
. That attempt also fails; however, the goal changes from p ∨ q ∨ r
to q ∨ r
.
When exactly does a subtactic in the first
combinator change the goal?
Jovan Gerbscheid (Apr 03 2025 at 13:08):
Did you mean to write
repeat (first | apply Or.inl; assumption | apply Or.inr; assumption)
Bulhwi Cha (Apr 03 2025 at 13:12):
No, that doesn't work.
Jovan Gerbscheid (Apr 03 2025 at 13:14):
It seems to match what you were describing. You say that the attempt to focus on the right goal fails. But the focussing on the right goal of course doesn't fail.
Jovan Gerbscheid (Apr 03 2025 at 13:14):
As in, apply Or.inr
is successful, so that is were the first
combinator stops
Bulhwi Cha (Apr 03 2025 at 13:15):
I'm not sure what the word "fail" really means in this context.
Jovan Gerbscheid (Apr 03 2025 at 13:15):
fail means that the tactic throws an error
Jovan Gerbscheid (Apr 03 2025 at 13:16):
apply Or.inl; assumption
throws an error because assumption
does. apply Or.inr
doesn't throw an error
Bulhwi Cha (Apr 03 2025 at 13:16):
From docs#Lean.Parser.Tactic.first:
def Lean.Parser.Tactic.first : ParserDescr
first | tac | ...
runs eachtac
until one succeeds, or else fails.
Jovan Gerbscheid (Apr 03 2025 at 13:17):
Oh, is the "runs each tac
" confusing? It doesn't actually run each tactic: it stops when one succeeds.
Bulhwi Cha (Apr 03 2025 at 13:28):
Jovan Gerbscheid said:
As in,
apply Or.inr
is successful, so that is were thefirst
combinator stops
Does apply Or.inr
succeed in the following example?
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
apply Or.inr
Bulhwi Cha (Apr 03 2025 at 13:29):
What exactly is the meaning of the word "succeed" in this context?
Jovan Gerbscheid (Apr 03 2025 at 13:29):
Yes, it succeeds because the tactic doesn't throw an error
Jovan Gerbscheid (Apr 03 2025 at 13:31):
Here is an example of a tactic that doesn't succeed:
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
apply trivial
Bulhwi Cha (Apr 03 2025 at 13:31):
I do get an error message from the first line of my example:
Messages here:
1:47:
unsolved goals
case h
p q r : Prop
hr : r
⊢ q ∨ r
Jovan Gerbscheid (Apr 03 2025 at 13:35):
This error message is not thrown by the apply
tactic. The apply tactic successfully applies, and then there are no more tactics left, so lean checks if all goals have been closed. That is what throws this error.
For example:
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
apply Or.inr
repeat sorry
doesn't throw an error (just a warning), while
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
apply trivial
repeat sorry
throws an error, because apply trivial
failed. So Lean doesn't even try to repeat sorry
.
Bulhwi Cha (Apr 03 2025 at 13:52):
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
first | apply Or.inr | exact Or.inr (Or.inr hr) -- unsolved goals
You're right. If apply Or.inr
in the above first
combinator failed, it'd run exact Or.inr (Or.inr hr)
, but it doesn't.
Bulhwi Cha (Apr 03 2025 at 14:04):
Bulhwi Cha said:
Consider the following example from Section Tactic Combinators of #tpil:
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by repeat (first | apply Or.inl; assumption | apply Or.inr | assumption)
The compound tactic first tries to solve the left disjunct,
p
, immediately by assumption. That attempt fails, and the goal remains the same. It then tries to focus on the right disjunct,q ∨ r
. That attempt also fails; however, the goal changes fromp ∨ q ∨ r
toq ∨ r
.
I should fix the above explanation as follows:
The
first
combinator tries to solve the left disjunct,p
, immediately by assumption. That attempt fails, and the goal remains the same. It then tries to focus on the right disjunct,q ∨ r
. That attempt succeeds, so the goal changes fromp ∨ q ∨ r
toq ∨ r
.The
repeat
combinator applies thefirst
combinator again. The second subtactic in thefirst
combinator succeeds, so the goal changes fromq ∨ r
tor
.The
repeat
combinator applies thefirst
combinator once again. The last subtactic infirst
combinator,assumption
, succeeds and closes the goal.
Therefore, the compound tactic is equivalent to the following sequence of the same first
combinators:
example (p q r : Prop) (hr : r) : p ∨ q ∨ r := by
first | apply Or.inl; assumption | apply Or.inr | assumption -- runs `apply Or.inr`
first | apply Or.inl; assumption | apply Or.inr | assumption -- runs `apply Or.inr`
first | apply Or.inl; assumption | apply Or.inr | assumption -- runs `assumption`
Bulhwi Cha (Apr 03 2025 at 14:31):
I'm glad that I asked about the first
combinator. Thanks for your answer!
Bulhwi Cha (Apr 04 2025 at 13:39):
From docs#Lean.Parser.Tactic.first:
def Lean.Parser.Tactic.first : ParserDescr
first | tac | ...
runs eachtac
until one succeeds, or else fails.
Should we change the description of the first
combinator as follows?
first | tac | ...
runs only the firsttac
that succeeds; it fails if none of them succeeds.
Bulhwi Cha (Apr 04 2025 at 13:59):
Jovan Gerbscheid said:
Oh, is the "runs each
tac
" confusing? It doesn't actually run each tactic: it stops when one succeeds.
To put it another way, first | tac | ...
tries to run each tac
until one succeeds, or else fails. I think we should change the description of it.
Jovan Gerbscheid (Apr 04 2025 at 14:32):
Yes, I think both of these options are a better description.
Kevin Buzzard (Apr 04 2025 at 14:36):
I don't think "runs only the first tac
that succeeds" is better than "runs each tac
until one succeeds"; in fact I think it's strictly worse. What first
does is exactly the latter thing (i.e. what it already says it does), not the former thing. I agree that the second clause is better though.
Last updated: May 02 2025 at 03:31 UTC