Replaces `@[eliminator]` with two attributes `@[induction_eliminator]` and `@[cases_eliminator]` for defining custom eliminators for the `induction` and `cases` tactics, respectively. Adds `Nat.recAux` and `Nat.casesAuxOn`, which are eliminators that are defeq to `Nat.rec` and `Nat.casesOn`, but these use `0` and `n + 1` rather than `Nat.zero` and `Nat.succ n`. For example, using `induction` to prove that the factorial function is positive now has the following goal states (thanks also to #3616 for the goal state after unfolding). ```lean example : 0 < fact x := by induction x with | zero => decide | succ x ih => /- x : Nat ih : 0 < fact x ⊢ 0 < fact (x + 1) -/ unfold fact /- ... ⊢ 0 < (x + 1) * fact x -/ simpa using ih ``` Thanks to @adamtopaz for initial work on splitting the `@[eliminator]` attribute.
179 lines
9.5 KiB
Text
179 lines
9.5 KiB
Text
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 0, "character": 20}}
|
||
{"rendered": "```lean\nα : Sort ?u\n⊢ α → α\n```",
|
||
"goals": ["α : Sort ?u\n⊢ α → α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 0, "character": 21}}
|
||
{"rendered": "```lean\nα : Sort ?u\n⊢ α → α\n```",
|
||
"goals": ["α : Sort ?u\n⊢ α → α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 3, "character": 2}}
|
||
{"rendered": "```lean\nα : Sort ?u\n⊢ α → α\n```",
|
||
"goals": ["α : Sort ?u\n⊢ α → α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 3, "character": 3}}
|
||
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
|
||
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 7, "character": 3}}
|
||
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
|
||
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 10, "character": 20}}
|
||
{"rendered": "```lean\nα : Sort ?u\n⊢ α → α\n```",
|
||
"goals": ["α : Sort ?u\n⊢ α → α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 15, "character": 9}}
|
||
{"rendered": "```lean\ncase zero\n⊢ 0 + 0 = 0\n```",
|
||
"goals": ["case zero\n⊢ 0 + 0 = 0"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 17, "character": 5}}
|
||
{"rendered":
|
||
"```lean\ncase succ\nn✝ : Nat\na✝ : 0 + n✝ = n✝\n⊢ 0 + (n✝ + 1) = n✝ + 1\n```",
|
||
"goals": ["case succ\nn✝ : Nat\na✝ : 0 + n✝ = n✝\n⊢ 0 + (n✝ + 1) = n✝ + 1"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 21, "character": 9}}
|
||
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
|
||
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 21, "character": 10}}
|
||
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
|
||
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 21, "character": 11}}
|
||
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
|
||
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 27, "character": 3}}
|
||
{"rendered": "```lean\nn m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = n\n```",
|
||
"goals": ["n m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = n"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 27, "character": 9}}
|
||
{"rendered": "```lean\nn m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = m\n```",
|
||
"goals": ["n m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = m"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 27, "character": 13}}
|
||
{"rendered": "no goals", "goals": []}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 34, "character": 3}}
|
||
{"rendered": "```lean\ncase zero\n⊢ 0 + 0 = 0\n```",
|
||
"goals": ["case zero\n⊢ 0 + 0 = 0"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 40, "character": 3}}
|
||
{"rendered":
|
||
"```lean\ncase zero\n⊢ 0 + 0 = 0\n```\n---\n```lean\ncase succ\nn✝ : Nat\na✝ : 0 + n✝ = n✝\n⊢ 0 + (n✝ + 1) = n✝ + 1\n```",
|
||
"goals":
|
||
["case zero\n⊢ 0 + 0 = 0",
|
||
"case succ\nn✝ : Nat\na✝ : 0 + n✝ = n✝\n⊢ 0 + (n✝ + 1) = n✝ + 1"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 44, "character": 3}}
|
||
{"rendered":
|
||
"```lean\ncase zero\n⊢ 0 + 0 = 0\n```\n---\n```lean\ncase succ\nn✝ : Nat\n⊢ 0 + (n✝ + 1) = n✝ + 1\n```",
|
||
"goals":
|
||
["case zero\n⊢ 0 + 0 = 0", "case succ\nn✝ : Nat\n⊢ 0 + (n✝ + 1) = n✝ + 1"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 48, "character": 3}}
|
||
{"rendered": "```lean\na b : Nat\n⊢ a = b\n```",
|
||
"goals": ["a b : Nat\n⊢ a = b"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 51, "character": 20}}
|
||
{"rendered": "```lean\nα : Sort ?u\n⊢ α → α\n```",
|
||
"goals": ["α : Sort ?u\n⊢ α → α"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 55, "character": 3}}
|
||
{"rendered":
|
||
"```lean\nα : Sort ?u\np : α → Prop\na b : α\ninst✝ : DecidablePred p\nh : ∀ {p : α → Prop} [inst : DecidablePred p], p a → p b\n⊢ p a\n```",
|
||
"goals":
|
||
["α : Sort ?u\np : α → Prop\na b : α\ninst✝ : DecidablePred p\nh : ∀ {p : α → Prop} [inst : DecidablePred p], p a → p b\n⊢ p a"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 61, "character": 3}}
|
||
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 63, "character": 3}}
|
||
{"rendered": "```lean\ncase right\n⊢ False\n```",
|
||
"goals": ["case right\n⊢ False"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 68, "character": 3}}
|
||
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 70, "character": 3}}
|
||
{"rendered": "```lean\ncase right\n⊢ False\n```",
|
||
"goals": ["case right\n⊢ False"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 78, "character": 29}}
|
||
{"rendered":
|
||
"```lean\nt a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + t * (n✝ + 1)\n```\n---\n```lean\nt a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)\n```\n---\n```lean\nt a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)\n```",
|
||
"goals":
|
||
["t a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + t * (n✝ + 1)",
|
||
"t a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)",
|
||
"t a n✝ : Nat\na✝ : t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 82, "character": 53}}
|
||
{"rendered":
|
||
"```lean\ncase nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)\n```",
|
||
"goals":
|
||
["case nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 82, "character": 54}}
|
||
{"rendered":
|
||
"```lean\ncase nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)\n```",
|
||
"goals":
|
||
["case nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 86, "character": 38}}
|
||
{"rendered": "no goals", "goals": []}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 89, "character": 39}}
|
||
null
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 93, "character": 16}}
|
||
{"rendered":
|
||
"```lean\ncase left\n⊢ True\n```\n---\n```lean\ncase right\n⊢ False\n```",
|
||
"goals": ["case left\n⊢ True", "case right\n⊢ False"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 97, "character": 8}}
|
||
{"rendered": "```lean\n| True = True\n```", "goals": ["| True = True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 99, "character": 4}}
|
||
{"rendered": "```lean\n| True = True\n```", "goals": ["| True = True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 101, "character": 2}}
|
||
{"rendered": "no goals", "goals": []}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 106, "character": 4}}
|
||
{"rendered": "```lean\n⊢ True\n```", "goals": ["⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 108, "character": 2}}
|
||
{"rendered": "```lean\n⊢ True\n```", "goals": ["⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 113, "character": 4}}
|
||
{"rendered": "```lean\n⊢ True\n```", "goals": ["⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 115, "character": 2}}
|
||
null
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 120, "character": 2}}
|
||
{"rendered": "```lean\n⊢ False\n```", "goals": ["⊢ False"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 124, "character": 17}}
|
||
{"rendered": "```lean\np q : Prop\nhp : p\nhq : q\nthis : q ∧ p\n⊢ p ∧ q\n```",
|
||
"goals": ["p q : Prop\nhp : p\nhq : q\nthis : q ∧ p\n⊢ p ∧ q"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 128, "character": 18}}
|
||
{"rendered": "```lean\np q : Prop\nhp : p\nhq : q\n⊢ id (p ∧ q)\n```",
|
||
"goals": ["p q : Prop\nhp : p\nhq : q\n⊢ id (p ∧ q)"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 133, "character": 3}}
|
||
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 133, "character": 4}}
|
||
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 139, "character": 34}}
|
||
{"rendered": "```lean\nx✝ : Nat\n⊢ True\n```", "goals": ["x✝ : Nat\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 142, "character": 34}}
|
||
{"rendered": "```lean\nx✝ : Nat\n⊢ True\n```", "goals": ["x✝ : Nat\n⊢ True"]}
|
||
{"textDocument": {"uri": "file:///plainGoal.lean"},
|
||
"position": {"line": 145, "character": 34}}
|
||
{"rendered": "```lean\nx✝ : Nat\n⊢ True\n```", "goals": ["x✝ : Nat\n⊢ True"]}
|