diff --git a/Std.lean b/Std.lean index 4a78963d77..9a570fe1a4 100644 --- a/Std.lean +++ b/Std.lean @@ -129,6 +129,7 @@ import Std.Tactic.Congr import Std.Tactic.Exact import Std.Tactic.Ext import Std.Tactic.Ext.Attr +import Std.Tactic.FalseOrByContra import Std.Tactic.GuardExpr import Std.Tactic.GuardMsgs import Std.Tactic.HaveI diff --git a/Std/Tactic/FalseOrByContra.lean b/Std/Tactic/FalseOrByContra.lean new file mode 100644 index 0000000000..f1251436bc --- /dev/null +++ b/Std/Tactic/FalseOrByContra.lean @@ -0,0 +1,45 @@ +/- +Copyright (c) 2023 Lean FRO, LLC. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Morrison +-/ +import Std.Lean.Expr +import Std.Lean.Meta.Basic + +/-! +# `false_or_by_contra` tactic + +Changes the goal to `False`, retaining as much information as possible: + +If the goal is `False`, do nothing. +If the goal is `¬ P`, introduce `P`. +If the goal is `x ≠ y`, introduce `x = y`. +Otherwise, for a goal `P`, replace it with `¬ ¬ P` and introduce `¬ P`. +-/ + +open Lean + +/-- +Changes the goal to `False`, retaining as much information as possible: + +If the goal is `False`, do nothing. +If the goal is `¬ P`, introduce `P`. +If the goal is `x ≠ y`, introduce `x = y`. +Otherwise, for a goal `P`, replace it with `¬ ¬ P` and introduce `¬ P`. +-/ +syntax (name := false_or_by_contra) "false_or_by_contra" : tactic + +open Meta Elab Tactic + +@[inherit_doc false_or_by_contra] +def falseOrByContra (g : MVarId) : MetaM MVarId := do + match ← whnfR (← g.getType) with + | .const ``False _ => pure g + | .app (.const ``Not _) _ + | .app (.const ``Ne _) _ => pure (← g.intro1).2 + | _ => + let [g] ← g.applyConst ``Classical.byContradiction | panic! "expected one sugoal" + pure (← g.intro1).2 + +@[inherit_doc falseOrByContra] +elab "false_or_by_contra" : tactic => liftMetaTactic1 (falseOrByContra ·) diff --git a/test/false_or_by_contra.lean b/test/false_or_by_contra.lean new file mode 100644 index 0000000000..a19d0956b7 --- /dev/null +++ b/test/false_or_by_contra.lean @@ -0,0 +1,25 @@ +import Std.Tactic.FalseOrByContra +import Std.Tactic.GuardExpr + +example (h : False) : False := by + false_or_by_contra + guard_target = False + exact h + +example (h : False) : x ≠ y := by + false_or_by_contra <;> rename_i h + guard_hyp h : x = y + guard_target = False + simp_all + +example (h : False) : ¬ P := by + false_or_by_contra <;> rename_i h + guard_hyp h : P + guard_target = False + simp_all + +example (h : False) : P := by + false_or_by_contra <;> rename_i h + guard_hyp h : ¬ P + guard_target = False + simp_all