When the `decide` tactic fails, it can try to give hints about the failure: - It tells you which `Decidable` instances it unfolded, by making use of the diagnostics feature. - If it encounters `Eq.rec`, it gives you a hint that one of these instances was likely defined using tactics. - If it encounters `Classical.choice`, it hints that you might have classical instances in scope. - During this, it tries to process `Decidable.rec`s and matchers to pin blame on a particular instance that failed to reduce. This idea comes from discussion with Heather Macbeth [on Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Decidable.20with.20structures/near/449409870).
104 lines
2.8 KiB
Text
104 lines
2.8 KiB
Text
/-!
|
|
# Tests of the `decide` tactic
|
|
-/
|
|
|
|
/-!
|
|
Success
|
|
-/
|
|
#guard_msgs in
|
|
example : 2 + 2 ≠ 5 := by decide
|
|
|
|
|
|
/-!
|
|
False proposition
|
|
-/
|
|
|
|
/--
|
|
error: tactic 'decide' proved that the proposition
|
|
1 ≠ 1
|
|
is false
|
|
-/
|
|
#guard_msgs in
|
|
example : 1 ≠ 1 := by decide
|
|
|
|
|
|
/-!
|
|
Irreducible decidable instance
|
|
-/
|
|
opaque unknownProp : Prop
|
|
|
|
/--
|
|
error: tactic 'decide' failed for proposition
|
|
unknownProp
|
|
since its 'Decidable' instance
|
|
Classical.propDecidable unknownProp
|
|
did not reduce to 'isTrue' or 'isFalse'.
|
|
|
|
After unfolding the instance 'Classical.propDecidable', reduction got stuck at the 'Decidable' instance
|
|
Classical.choice ⋯
|
|
|
|
Hint: Reduction got stuck on 'Classical.choice', which indicates that a 'Decidable' instance is
|
|
defined using classical reasoning, proving an instance exists rather than giving a concrete
|
|
construction. The 'decide' tactic works by evaluating a decision procedure via reduction, and it
|
|
cannot make progress with such instances. This can occur due to the 'opened scoped Classical'
|
|
command, which enables the instance 'Classical.propDecidable'.
|
|
-/
|
|
#guard_msgs in
|
|
open scoped Classical in
|
|
example : unknownProp := by decide
|
|
|
|
|
|
/-!
|
|
Reporting unfolded instances and give hint about Eq.rec.
|
|
From discussion with Heather Macbeth on Zulip
|
|
-/
|
|
structure Nice (n : Nat) : Prop :=
|
|
(large : 100 ≤ n)
|
|
|
|
theorem nice_iff (n : Nat) : Nice n ↔ 100 ≤ n := ⟨Nice.rec id, Nice.mk⟩
|
|
|
|
def baz (n : Nat) : Decidable (Nice n) := by
|
|
rw [nice_iff]
|
|
infer_instance
|
|
|
|
instance : Decidable (Nice n) := baz n
|
|
|
|
/--
|
|
error: tactic 'decide' failed for proposition
|
|
Nice 102
|
|
since its 'Decidable' instance
|
|
instDecidableNice
|
|
did not reduce to 'isTrue' or 'isFalse'.
|
|
|
|
After unfolding the instances 'baz' and 'instDecidableNice', reduction got stuck at the 'Decidable' instance
|
|
⋯ ▸ inferInstance
|
|
|
|
Hint: Reduction got stuck on '▸' (Eq.rec), which suggests that one of the 'Decidable' instances is
|
|
defined using tactics such as 'rw' or 'simp'. To avoid tactics, make use of functions such as
|
|
'inferInstanceAs' or 'decidable_of_decidable_of_iff' to alter a proposition.
|
|
-/
|
|
#guard_msgs in
|
|
example : Nice 102 := by decide
|
|
|
|
|
|
/-!
|
|
Following `Decidable.rec` to give better messages
|
|
-/
|
|
|
|
/--
|
|
error: tactic 'decide' failed for proposition
|
|
¬Nice 102
|
|
since its 'Decidable' instance
|
|
instDecidableNot
|
|
did not reduce to 'isTrue' or 'isFalse'.
|
|
|
|
After unfolding the instances 'baz', 'instDecidableNice' and 'instDecidableNot', reduction got stuck
|
|
at the 'Decidable' instance
|
|
⋯ ▸ inferInstance
|
|
|
|
Hint: Reduction got stuck on '▸' (Eq.rec), which suggests that one of the 'Decidable' instances is
|
|
defined using tactics such as 'rw' or 'simp'. To avoid tactics, make use of functions such as
|
|
'inferInstanceAs' or 'decidable_of_decidable_of_iff' to alter a proposition.
|
|
-/
|
|
#guard_msgs in
|
|
example : ¬ Nice 102 := by decide
|