This PR adds the `binderNameHint` gadget. It can be used in rewrite and
simp rules to preserve a user-provided name where possible.
The expression `binderNameHint v binder e` defined to be `e`.
If it is used on the right-hand side of an equation that is applied by a
tactic like `rw` or `simp`,
and `v` is a local variable, and `binder` is an expression that (after
beta-reduction) is a binder
(so `fun w => …` or `∀ w, …`), then it will rename `v` to the name used
in the binder, and remove
the `binderNameHint`.
A typical use of this gadget would be as follows; the gadget ensures
that after rewriting, the local
variable is still `name`, and not `x`:
```
theorem all_eq_not_any_not (l : List α) (p : α → Bool) :
l.all p = !l.any fun x => binderNameHint x p (!p x) := sorry
example (names : List String) : names.all (fun name => "Waldo".isPrefixOf name) = true := by
rw [all_eq_not_any_not]
-- ⊢ (!names.any fun name => !"Waldo".isPrefixOf name) = true
```
This gadget is supported by `simp`, `dsimp` and `rw` in the
right-hand-side of an equation, but not
in hypotheses or by other tactics.
28 lines
945 B
Text
28 lines
945 B
Text
import Lean
|
||
|
||
-- This checks that binderNameHint freshens up a variable.:
|
||
|
||
axiom allPairs (l : List α) (p : α → α → Bool) : Bool
|
||
|
||
#guard_msgs (drop warning) in
|
||
theorem all_eq_allPairs (l : List α) (p : α → Bool) :
|
||
l.all p ↔ ∀ x y z, binderNameHint x p <| binderNameHint y () <| p x && p y && p z:= sorry
|
||
|
||
-- below we should get `a` from the user (no dagger), `y` with dagger (binderNameHint added a macro
|
||
-- scope) and `z` without dagger (because intro1P is not hygienic)
|
||
|
||
/--
|
||
error: tactic 'fail' failed
|
||
f : String → Bool
|
||
names : List String
|
||
a y✝ z : String
|
||
⊢ (f a && f y✝ && f z) = true
|
||
-/
|
||
#guard_msgs in
|
||
open Lean Elab Tactic in
|
||
example {f : String → Bool} (names : List String) : names.all (fun a => f a) = true := by
|
||
rw [all_eq_allPairs]
|
||
run_tac liftMetaTactic1 ((some ·.2) <$> ·.intro1P)
|
||
run_tac liftMetaTactic1 ((some ·.2) <$> ·.intro1P)
|
||
run_tac liftMetaTactic1 ((some ·.2) <$> ·.intro1P)
|
||
fail
|