Zulip Chat Archive
Stream: new members
Topic: syntax to negate a propositional hypothesis?
Daniel Windham (Feb 05 2024 at 18:54):
Dumb question - given a hypothesis such as h : 1 + 1 = 3
, how do I construct its negation ¬ h
?
I'm getting an error
application type mismatch
¬h
argument
h
has type
1 + 1 = 3 : Prop
but is expected to have type
Prop : Type
Here's the full code example:
theorem demo (h: 1 + 1 = 3) : false := by
have h2: ¬ h := by
sorry
contradiction
Related vocabulary question - in informal conversation, is there a precise way to say that the type of the type of h
is Prop
? I wrote "propositional hypothesis" in my topic title but I don't know if that means what I want.
Thanks!
Jireh Loreaux (Feb 05 2024 at 18:56):
The type of h
is not Prop
. The type of h
is 1 + 1 = 3
, that's exactly what h : 1 + 1 = 3
means. Here h
is proof that 1 + 1 = 3
.
Jireh Loreaux (Feb 05 2024 at 18:56):
That's why you can't write ¬ h
, because ¬ : Prop → Prop
. You can't take the negation of a proof.
Daniel Windham (Feb 05 2024 at 19:03):
@Jireh Loreaux it sounds like I'm stuck on something deeper then. I am trying to construct a proof by contradiction. If I write have h2: ¬ (1 + 1 = 3)
in my original example, the proof by contradiction completes. I'd rather write h2
in terms of h1
because it will be more concise. In my real example, h1
is a lot longer to write out. Does Lean provide a way to write h2
in terms of h1
?
Richard Copley (Feb 05 2024 at 19:40):
You could do something like the following, but it's less useful than you might think.
def TypeOf {α : Sort*} (x : α) := α
theorem demo (h: 1 + 1 = 3) : False := by
have h2: ¬ (TypeOf h) := by
unfold TypeOf
-- ⊢ ¬1 + 1 = 3
sorry
contradiction
It's easier to use the contrapose
tactic:
theorem demo (h: 1 + 1 = 3) : False := by
contrapose h
-- ⊢ ¬1 + 1 = 3
sorry
Daniel Windham (Feb 05 2024 at 19:43):
Thanks @Richard Copley , that's what I was looking for.
Agreed that contrapose
usually makes more sense. However, I don't have contrapose right now because I'm working in the std library. (Perhaps contrapose belongs in std, I haven't gone and asked anyone yet...)
Patrick Massot (Feb 05 2024 at 19:45):
contrapose
is a tiny tactic that could very easily move to std or your own code. The more complicated bit is contrapose!
.
Richard Copley (Feb 05 2024 at 19:45):
Or there's this:
theorem demo (h: 1 + 1 = 3) : False := by
revert h
-- 1 + 1 = 3 → False
sorry
Patrick Massot (Feb 05 2024 at 19:46):
Hopefully you can simply drop
namespace Mathlib.Tactic.Contrapose
lemma mtr {p q : Prop} : (¬ q → ¬ p) → (p → q) := fun h hp ↦ by_contra (fun h' ↦ h h' hp)
/--
Transforms the goal into its contrapositive.
* `contrapose` turns a goal `P → Q` into `¬ Q → ¬ P`
* `contrapose h` first reverts the local assumption `h`, and then uses `contrapose` and `intro h`
* `contrapose h with new_h` uses the name `new_h` for the introduced hypothesis
-/
syntax (name := contrapose) "contrapose" (ppSpace colGt ident (" with " ident)?)? : tactic
macro_rules
| `(tactic| contrapose) => `(tactic| (refine mtr ?_))
| `(tactic| contrapose $e) => `(tactic| (revert $e:ident; contrapose; intro $e:ident))
| `(tactic| contrapose $e with $e') => `(tactic| (revert $e:ident; contrapose; intro $e':ident))
into your current file.
Jireh Loreaux (Feb 05 2024 at 19:58):
Also, since you're in Std
, you can just use omega
to close this goal:
import Std
theorem demo (h : 1 + 1 = 3) : false := by omega
Daniel Windham (Feb 05 2024 at 19:58):
@Patrick Massot it looks like there are a few more missing definitions in std:
lemma
errors with unexpected identifier; expected command
. I assume this is an alias for theorem
defined outside of std. I replaced it with theorem
, at which point I hit the next error:
by_contra
errors with unknown identifier 'by_contra'
. Is this definition easy to pull from Mathlib? I'm not sure what to make of this, since I can use by_contra
as a tactic within a proof.
Eric Wieser (Feb 05 2024 at 19:59):
Richard Copley said:
You could do something like the following, but it's less useful than you might think.
def TypeOf {α : Sort*} (x : α) := α
This is builtin to Lean as type_of% x
, which unfolds immediately
Richard Copley (Feb 05 2024 at 20:09):
Daniel Windham said:
I'm not sure what to make of this, since I can use
by_contra
as a tactic within a proof.
The tactic by_contra
is in Std.Tactic.Basic
, but the ("term-mode") function by_contra
is in Mathlib.Logic.Basic
.
Patrick Massot (Feb 05 2024 at 20:11):
theorem mtr {p q : Prop} : (¬ q → ¬ p) → (p → q) :=
fun h hp ↦ Decidable.byCases (dec := Classical.propDecidable _) id fun nq ↦ (h nq hp).elim
Kyle Miller (Feb 05 2024 at 20:16):
@Jireh Loreaux Or there's theorem demo (h : 1 + 1 = 3) : false := by cases h
since there are no free variables (it analyzes the constructors).
Daniel Windham (Feb 05 2024 at 20:17):
Patrick Massot said:
theorem mtr {p q : Prop} : (¬ q → ¬ p) → (p → q) := fun h hp ↦ Decidable.byCases (dec := Classical.propDecidable _) id fun nq ↦ (h nq hp).elim
Thanks @Patrick Massot that works now.
Jireh Loreaux (Feb 05 2024 at 20:23):
@Kyle Miller what fun is a mallet when you have a sledgehammer? :wink: (joking of course)
Matt Diamond (Feb 05 2024 at 20:52):
@Daniel Windham maybe I'm off base but it sounds like you're really just trying to do this:
def P : Prop := [very long and complicated proposition]
theorem demo (h1 : P) : false := by
have h2: ¬ P := by
sorry
contradiction
There's no need for type_of%
or anything like that. The key to writing h2
in terms of h1
is to abstract out the common element into its own definition.
Daniel Windham (Feb 05 2024 at 21:19):
@Matt Diamond thanks, that's a good trick. That's not quite my situation here, since the complicated proposition is the result of unfolding (and simplifying) subexpressions in the theorem's hypothesis. Is there a tactic to abstract out a subexpression from an existing goal or hypothesis in the proof state? I'd like to do something like this:
theorem demo ... := by
simp [...]
intro h
let len := fun (x: AssocList α β) => List.length (AssocList.toList x) -- define the subexpression
rw [len] -- replace the subexpression in the goal with `len`
rw [len] at h -- replace the subexpression in `h` with `len`
Matt Diamond (Feb 05 2024 at 21:23):
maybe the set
tactic? it's like let
but it replaces expressions with the newly defined variable where it can
Daniel Windham (Feb 05 2024 at 21:28):
Ah perfect, set
is what I was looking for. (Though it's another tactic that's not in std lib, hmm...) Thanks @Matt Diamond!
Matt Diamond (Feb 05 2024 at 21:29):
no problem!
Daniel Windham (Feb 05 2024 at 22:10):
Here's a way to do this without set
. This is what set
does under the hood:
theorem demo (h: 1 + 1 = 3) : 1 + 1 + 1 + 1 + 1 = 6 := by
let z := 1 + 1
let hh: z = 1 + 1 := by rfl -- construct an equality corresponding to the new definition
rw [← hh]
rw [← hh] at h
Last updated: May 02 2025 at 03:31 UTC