Built with doc-gen4, running Lean4. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓to navigate, Ctrl+πŸ–±οΈto focus. On Mac, use Cmdinstead of Ctrl.
/-
Copyright (c) 2019 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot, Simon Hudon, Alice Laroche, FrΓ©dΓ©ric Dupuis, Jireh Loreaux
-/

import Lean
import Mathlib.Lean.Expr
import Mathlib.Logic.Basic
import Mathlib.Init.Algebra.Order
import Mathlib.Tactic.Conv

namespace Mathlib.Tactic.PushNeg

open Lean Meta Elab.Tactic Parser.Tactic

variable (
p: Prop
p
q: Prop
q
:
Prop: Type
Prop
) (
s: Ξ± β†’ Prop
s
:
Ξ±: ?m.766
Ξ±
β†’
Prop: Type
Prop
) theorem
not_not_eq: (¬¬p) = p
not_not_eq
: (Β¬ Β¬
p: Prop
p
) =
p: Prop
p
:=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_not: βˆ€ {a : Prop}, ¬¬a ↔ a
not_not
theorem
not_and_eq: (Β¬(p ∧ q)) = (p β†’ Β¬q)
not_and_eq
: (Β¬ (
p: Prop
p
∧
q: Prop
q
)) = (
p: Prop
p
β†’ Β¬
q: Prop
q
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_and: βˆ€ {a b : Prop}, Β¬(a ∧ b) ↔ a β†’ Β¬b
not_and
theorem
not_and_or_eq: (¬(p ∧ q)) = (¬p ∨ ¬q)
not_and_or_eq
: (Β¬ (
p: Prop
p
∧
q: Prop
q
)) = (Β¬
p: Prop
p
∨ ¬
q: Prop
q
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_and_or: βˆ€ {a b : Prop}, Β¬(a ∧ b) ↔ Β¬a ∨ Β¬b
not_and_or
theorem
not_or_eq: (¬(p ∨ q)) = (¬p ∧ ¬q)
not_or_eq
: (Β¬ (
p: Prop
p
∨
q: Prop
q
)) = (Β¬
p: Prop
p
∧ ¬
q: Prop
q
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_or: βˆ€ {p q : Prop}, Β¬(p ∨ q) ↔ Β¬p ∧ Β¬q
not_or
theorem
not_forall_eq: βˆ€ {Ξ± : Sort u_1} (s : Ξ± β†’ Prop), (Β¬βˆ€ (x : Ξ±), s x) = βˆƒ x, Β¬s x
not_forall_eq
: (Β¬ βˆ€
x: ?m.183
x
,
s: Ξ± β†’ Prop
s
x: ?m.183
x
) = (βˆƒ
x: ?m.190
x
, Β¬
s: Ξ± β†’ Prop
s
x: ?m.190
x
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_forall: βˆ€ {Ξ± : Sort ?u.201} {p : Ξ± β†’ Prop}, (Β¬βˆ€ (x : Ξ±), p x) ↔ βˆƒ x, Β¬p x
not_forall
theorem
not_exists_eq: (Β¬βˆƒ x, s x) = βˆ€ (x : Ξ±), Β¬s x
not_exists_eq
: (Β¬ βˆƒ
x: ?m.241
x
,
s: Ξ± β†’ Prop
s
x: ?m.241
x
) = (βˆ€
x: ?m.246
x
, Β¬
s: Ξ± β†’ Prop
s
x: ?m.246
x
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_exists: βˆ€ {Ξ± : Sort ?u.257} {p : Ξ± β†’ Prop}, (Β¬βˆƒ x, p x) ↔ βˆ€ (x : Ξ±), Β¬p x
not_exists
theorem
not_implies_eq: (Β¬(p β†’ q)) = (p ∧ Β¬q)
not_implies_eq
: (Β¬ (
p: Prop
p
β†’
q: Prop
q
)) = (
p: Prop
p
∧ ¬
q: Prop
q
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_imp: βˆ€ {a b : Prop}, Β¬(a β†’ b) ↔ a ∧ Β¬b
not_imp
theorem
not_ne_eq: βˆ€ (x y : Ξ±), (Β¬x β‰  y) = (x = y)
not_ne_eq
(
x: Ξ±
x
y: Ξ±
y
:
Ξ±: ?m.321
Ξ±
) : (Β¬ (
x: Ξ±
x
β‰ 
y: Ξ±
y
)) = (
x: Ξ±
x
=
y: Ξ±
y
) :=
ne_eq: βˆ€ {Ξ± : Sort ?u.345} (a b : Ξ±), (a β‰  b) = Β¬a = b
ne_eq
x: Ξ±
x
y: Ξ±
y
β–Έ
not_not_eq: βˆ€ (p : Prop), (¬¬p) = p
not_not_eq
_: Prop
_
variable {
Ξ²: Type u
Ξ²
:
Type u: Type (u+1)
Type u
} [
LinearOrder: Type ?u.385 β†’ Type ?u.385
LinearOrder
Ξ²: Type u
Ξ²
] theorem
not_le_eq: βˆ€ (a b : Ξ²), (Β¬a ≀ b) = (b < a)
not_le_eq
(
a: Ξ²
a
b: Ξ²
b
:
Ξ²: Type u
Ξ²
) : (Β¬ (
a: Ξ²
a
≀
b: Ξ²
b
)) = (
b: Ξ²
b
<
a: Ξ²
a
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_le: βˆ€ {Ξ± : Type ?u.461} [inst : LinearOrder Ξ±] {a b : Ξ±}, Β¬a ≀ b ↔ b < a
not_le
theorem
not_lt_eq: βˆ€ (a b : Ξ²), (Β¬a < b) = (b ≀ a)
not_lt_eq
(
a: Ξ²
a
b: Ξ²
b
:
Ξ²: Type u
Ξ²
) : (Β¬ (
a: Ξ²
a
<
b: Ξ²
b
)) = (
b: Ξ²
b
≀
a: Ξ²
a
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_lt: βˆ€ {Ξ± : Type ?u.554} [inst : LinearOrder Ξ±] {a b : Ξ±}, Β¬a < b ↔ b ≀ a
not_lt
theorem
not_ge_eq: βˆ€ (a b : Ξ²), (Β¬a β‰₯ b) = (a < b)
not_ge_eq
(
a: Ξ²
a
b: Ξ²
b
:
Ξ²: Type u
Ξ²
) : (Β¬ (
a: Ξ²
a
β‰₯
b: Ξ²
b
)) = (
a: Ξ²
a
<
b: Ξ²
b
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_le: βˆ€ {Ξ± : Type ?u.647} [inst : LinearOrder Ξ±] {a b : Ξ±}, Β¬a ≀ b ↔ b < a
not_le
theorem
not_gt_eq: βˆ€ (a b : Ξ²), (Β¬a > b) = (a ≀ b)
not_gt_eq
(
a: Ξ²
a
b: Ξ²
b
:
Ξ²: Type u
Ξ²
) : (Β¬ (
a: Ξ²
a
>
b: Ξ²
b
)) = (
a: Ξ²
a
≀
b: Ξ²
b
) :=
propext: βˆ€ {a b : Prop}, (a ↔ b) β†’ a = b
propext
not_lt: βˆ€ {Ξ± : Type ?u.740} [inst : LinearOrder Ξ±] {a b : Ξ±}, Β¬a < b ↔ b ≀ a
not_lt
/-- Make `push_neg` use `not_and_or` rather than the default `not_and`. -/ register_option
push_neg.use_distrib: Lean.Option Bool
push_neg.use_distrib
:
Bool: Type
Bool
:= { defValue :=
false: Bool
false
group :=
"": String
""
descr :=
"Make `push_neg` use `not_and_or` rather than the default `not_and`.": String
"Make `push_neg` use `not_and_or` rather than the default `not_and`."
} /-- Push negations at the top level of the current expression. -/ def
transformNegationStep: Expr β†’ SimpM (Option Simp.Step)
transformNegationStep
(
e: Expr
e
:
Expr: Type
Expr
) :
SimpM: Type β†’ Type
SimpM
(
Option: Type ?u.925 β†’ Type ?u.925
Option
Simp.Step: Type
Simp.Step
) := do let
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(
e: Expr
e
:
Expr: Type
Expr
) (
pf: Expr
pf
:
Expr: Type
Expr
) :
Simp.Step: Type
Simp.Step
:=
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
{ expr :=
e: Expr
e
, proof? :=
some: {Ξ± : Type ?u.1255} β†’ Ξ± β†’ Option Ξ±
some
pf: Expr
pf
} let
e_whnf: ?m.1407
e_whnf
←
whnfR: Expr β†’ MetaM Expr
whnfR
e: Expr
e
let
some: {Ξ± : Type ?u.967} β†’ Ξ± β†’ Option Ξ±
some
ex: Expr
ex
:=
e_whnf: ?m.1407
e_whnf
.
not?: Expr β†’ Option Expr
not?
| return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
{ expr :=
e: Expr
e
} match
ex: Expr
ex
.
getAppFnArgs: Expr β†’ Name Γ— Array Expr
getAppFnArgs
with | (
``Not: Name
``
Not: Prop β†’ Prop
Not
, #[
e: Expr
e
]) => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
e: Expr
e
(← mkAppM ``not_not_eq #[e]): ?m.1533
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_not_eq #[e]): ?m.1533
``
not_not_eq: βˆ€ (p : Prop), (¬¬p) = p
not_not_eq
(← mkAppM ``not_not_eq #[e]): ?m.1533
#[
e: Expr
e
(← mkAppM ``not_not_eq #[e]): ?m.1533
])
| (
``And: Name
``
And: Prop β†’ Prop β†’ Prop
And
, #[
p: Expr
p
,
q: Expr
q
]) => match ←
getBoolOption: {m : Type β†’ Type} β†’ [inst : Monad m] β†’ [inst : MonadOptions m] β†’ Name β†’ optParam Bool false β†’ m Bool
getBoolOption
`push_neg.use_distrib: Name
`push_neg.use_distrib
with |
false: Bool
false
=> return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(
.forallE: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.forallE
`_: Name
`_
p: Expr
p
(
mkNot: Expr β†’ Expr
mkNot
q: Expr
q
)
default: {Ξ± : Sort ?u.1966} β†’ [self : Inhabited Ξ±] β†’ Ξ±
default
)
(←mkAppM ``not_and_eq #[p, q]): ?m.1939
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(←mkAppM ``not_and_eq #[p, q]): ?m.1939
``
not_and_eq: βˆ€ (p q : Prop), (Β¬(p ∧ q)) = (p β†’ Β¬q)
not_and_eq
(←mkAppM ``not_and_eq #[p, q]): ?m.1939
#[
p: Expr
p
(←mkAppM ``not_and_eq #[p, q]): ?m.1939
,
q: Expr
q
(←mkAppM ``not_and_eq #[p, q]): ?m.1939
])
|
true: Bool
true
=> return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(
mkOr: Expr β†’ Expr β†’ Expr
mkOr
(
mkNot: Expr β†’ Expr
mkNot
p: Expr
p
) (
mkNot: Expr β†’ Expr
mkNot
q: Expr
q
))
(←mkAppM ``not_and_or_eq #[p, q]): ?m.2211
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(←mkAppM ``not_and_or_eq #[p, q]): ?m.2211
``
not_and_or_eq: βˆ€ (p q : Prop), (Β¬(p ∧ q)) = (Β¬p ∨ Β¬q)
not_and_or_eq
(←mkAppM ``not_and_or_eq #[p, q]): ?m.2211
#[
p: Expr
p
(←mkAppM ``not_and_or_eq #[p, q]): ?m.2211
,
q: Expr
q
(←mkAppM ``not_and_or_eq #[p, q]): ?m.2211
])
| (
``Or: Name
``
Or: Prop β†’ Prop β†’ Prop
Or
, #[
p: Expr
p
,
q: Expr
q
]) => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(
mkAnd: Expr β†’ Expr β†’ Expr
mkAnd
(
mkNot: Expr β†’ Expr
mkNot
p: Expr
p
) (
mkNot: Expr β†’ Expr
mkNot
q: Expr
q
))
(←mkAppM ``not_or_eq #[p, q]): ?m.2622
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(←mkAppM ``not_or_eq #[p, q]): ?m.2622
``
not_or_eq: βˆ€ (p q : Prop), (Β¬(p ∨ q)) = (Β¬p ∧ Β¬q)
not_or_eq
(←mkAppM ``not_or_eq #[p, q]): ?m.2622
#[
p: Expr
p
(←mkAppM ``not_or_eq #[p, q]): ?m.2622
,
q: Expr
q
(←mkAppM ``not_or_eq #[p, q]): ?m.2622
])
| (
``Eq: Name
``
Eq: {Ξ± : Sort u_1} β†’ Ξ± β†’ Ξ± β†’ Prop
Eq
, #[
_ty: Expr
_ty
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
{ expr := ← mkAppM ``Ne #[e₁, eβ‚‚] }: Simp.Result
{ expr := ←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
{ expr := ← mkAppM ``Ne #[e₁, eβ‚‚] }: Simp.Result
``
Ne: {Ξ± : Sort u} β†’ Ξ± β†’ Ξ± β†’ Prop
Ne
{ expr := ← mkAppM ``Ne #[e₁, eβ‚‚] }: Simp.Result
#[
e₁: Expr
e₁
{ expr := ← mkAppM ``Ne #[e₁, eβ‚‚] }: Simp.Result
,
eβ‚‚: Expr
eβ‚‚
{ expr := ← mkAppM ``Ne #[e₁, eβ‚‚] }: Simp.Result
] }
| (
``Ne: Name
``
Ne: {Ξ± : Sort u} β†’ Ξ± β†’ Ξ± β†’ Prop
Ne
, #[
_ty: Expr
_ty
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``Eq #[e₁, eβ‚‚]): ?m.3128
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``Eq #[e₁, eβ‚‚]): ?m.3128
``
Eq: {Ξ± : Sort u_1} β†’ Ξ± β†’ Ξ± β†’ Prop
Eq
(← mkAppM ``Eq #[e₁, eβ‚‚]): ?m.3128
#[
e₁: Expr
e₁
(← mkAppM ``Eq #[e₁, eβ‚‚]): ?m.3128
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``Eq #[e₁, eβ‚‚]): ?m.3128
])
(← mkAppM ``not_ne_eq #[e₁, eβ‚‚]): ?m.3196
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_ne_eq #[e₁, eβ‚‚]): ?m.3196
``
not_ne_eq: βˆ€ {Ξ± : Sort u_1} (x y : Ξ±), (Β¬x β‰  y) = (x = y)
not_ne_eq
(← mkAppM ``not_ne_eq #[e₁, eβ‚‚]): ?m.3196
#[
e₁: Expr
e₁
(← mkAppM ``not_ne_eq #[e₁, eβ‚‚]): ?m.3196
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``not_ne_eq #[e₁, eβ‚‚]): ?m.3196
])
| (
``LE.le: Name
``
LE.le: {Ξ± : Type u} β†’ [self : LE Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LE.le
, #[
ty: Expr
ty
,
_inst: Expr
_inst
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => let
linOrd: ?m.3492
linOrd
←
synthInstance?: Expr β†’ optParam (Option Nat) none β†’ MetaM (Option Expr)
synthInstance?
(← mkAppM ``LinearOrder #[ty]): ?m.3438
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LinearOrder #[ty]): ?m.3438
``
LinearOrder: Type u β†’ Type u
LinearOrder
(← mkAppM ``LinearOrder #[ty]): ?m.3438
#[
ty: Expr
ty
(← mkAppM ``LinearOrder #[ty]): ?m.3438
])
match
linOrd: ?m.3492
linOrd
with |
some: {Ξ± : Type ?u.3494} β†’ Ξ± β†’ Option Ξ±
some
_ => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``LT.lt #[eβ‚‚, e₁]): ?m.3575
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LT.lt #[eβ‚‚, e₁]): ?m.3575
``
LT.lt: {Ξ± : Type u} β†’ [self : LT Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LT.lt
(← mkAppM ``LT.lt #[eβ‚‚, e₁]): ?m.3575
#[
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``LT.lt #[eβ‚‚, e₁]): ?m.3575
,
e₁: Expr
e₁
(← mkAppM ``LT.lt #[eβ‚‚, e₁]): ?m.3575
])
(← mkAppM ``not_le_eq #[e₁, eβ‚‚]): ?m.3643
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_le_eq #[e₁, eβ‚‚]): ?m.3643
``
not_le_eq: βˆ€ {Ξ² : Type u} [inst : LinearOrder Ξ²] (a b : Ξ²), (Β¬a ≀ b) = (b < a)
not_le_eq
(← mkAppM ``not_le_eq #[e₁, eβ‚‚]): ?m.3643
#[
e₁: Expr
e₁
(← mkAppM ``not_le_eq #[e₁, eβ‚‚]): ?m.3643
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``not_le_eq #[e₁, eβ‚‚]): ?m.3643
])
|
none: {Ξ± : Type ?u.3754} β†’ Option Ξ±
none
=> return
none: {Ξ± : Type ?u.3787} β†’ Option Ξ±
none
| (
``LT.lt: Name
``
LT.lt: {Ξ± : Type u} β†’ [self : LT Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LT.lt
, #[
ty: Expr
ty
,
_inst: Expr
_inst
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => let
linOrd: ?m.4196
linOrd
←
synthInstance?: Expr β†’ optParam (Option Nat) none β†’ MetaM (Option Expr)
synthInstance?
(← mkAppM ``LinearOrder #[ty]): ?m.4142
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LinearOrder #[ty]): ?m.4142
``
LinearOrder: Type u β†’ Type u
LinearOrder
(← mkAppM ``LinearOrder #[ty]): ?m.4142
#[
ty: Expr
ty
(← mkAppM ``LinearOrder #[ty]): ?m.4142
])
match
linOrd: ?m.4196
linOrd
with |
some: {Ξ± : Type ?u.1136} β†’ Ξ± β†’ Option Ξ±
some
_ => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``LE.le #[eβ‚‚, e₁]): ?m.4279
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LE.le #[eβ‚‚, e₁]): ?m.4279
``
LE.le: {Ξ± : Type u} β†’ [self : LE Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LE.le
(← mkAppM ``LE.le #[eβ‚‚, e₁]): ?m.4279
#[
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``LE.le #[eβ‚‚, e₁]): ?m.4279
,
e₁: Expr
e₁
(← mkAppM ``LE.le #[eβ‚‚, e₁]): ?m.4279
])
(← mkAppM ``not_lt_eq #[e₁, eβ‚‚]): ?m.4347
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_lt_eq #[e₁, eβ‚‚]): ?m.4347
``
not_lt_eq: βˆ€ {Ξ² : Type u} [inst : LinearOrder Ξ²] (a b : Ξ²), (Β¬a < b) = (b ≀ a)
not_lt_eq
(← mkAppM ``not_lt_eq #[e₁, eβ‚‚]): ?m.4347
#[
e₁: Expr
e₁
(← mkAppM ``not_lt_eq #[e₁, eβ‚‚]): ?m.4347
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``not_lt_eq #[e₁, eβ‚‚]): ?m.4347
])
|
none: {Ξ± : Type ?u.4514} β†’ Option Ξ±
none
=> return
none: {Ξ± : Type ?u.4547} β†’ Option Ξ±
none
| (
``GE.ge: Name
``
GE.ge: {Ξ± : Type u} β†’ [inst : LE Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
GE.ge
, #[
ty: Expr
ty
,
_inst: Expr
_inst
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => let
linOrd: ?m.4810
linOrd
←
synthInstance?: Expr β†’ optParam (Option Nat) none β†’ MetaM (Option Expr)
synthInstance?
(← mkAppM ``LinearOrder #[ty]): ?m.4756
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LinearOrder #[ty]): ?m.4756
``
LinearOrder: Type u β†’ Type u
LinearOrder
(← mkAppM ``LinearOrder #[ty]): ?m.4756
#[
ty: Expr
ty
(← mkAppM ``LinearOrder #[ty]): ?m.4756
])
match
linOrd: ?m.4810
linOrd
with |
some: {Ξ± : Type ?u.4812} β†’ Ξ± β†’ Option Ξ±
some
_ => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``LT.lt #[e₁, eβ‚‚]): ?m.4892
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LT.lt #[e₁, eβ‚‚]): ?m.4892
``
LT.lt: {Ξ± : Type u} β†’ [self : LT Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LT.lt
(← mkAppM ``LT.lt #[e₁, eβ‚‚]): ?m.4892
#[
e₁: Expr
e₁
(← mkAppM ``LT.lt #[e₁, eβ‚‚]): ?m.4892
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``LT.lt #[e₁, eβ‚‚]): ?m.4892
])
(← mkAppM ``not_ge_eq #[e₁, eβ‚‚]): ?m.4960
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_ge_eq #[e₁, eβ‚‚]): ?m.4960
``
not_ge_eq: βˆ€ {Ξ² : Type u} [inst : LinearOrder Ξ²] (a b : Ξ²), (Β¬a β‰₯ b) = (a < b)
not_ge_eq
(← mkAppM ``not_ge_eq #[e₁, eβ‚‚]): ?m.4960
#[
e₁: Expr
e₁
(← mkAppM ``not_ge_eq #[e₁, eβ‚‚]): ?m.4960
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``not_ge_eq #[e₁, eβ‚‚]): ?m.4960
])
|
none: {Ξ± : Type ?u.5071} β†’ Option Ξ±
none
=> return
none: {Ξ± : Type ?u.5104} β†’ Option Ξ±
none
| (
``GT.gt: Name
``
GT.gt: {Ξ± : Type u} β†’ [inst : LT Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
GT.gt
, #[
ty: Expr
ty
,
_inst: Expr
_inst
,
e₁: Expr
e₁
,
eβ‚‚: Expr
eβ‚‚
]) => let
linOrd: ?m.5367
linOrd
←
synthInstance?: Expr β†’ optParam (Option Nat) none β†’ MetaM (Option Expr)
synthInstance?
(← mkAppM ``LinearOrder #[ty]): ?m.5313
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LinearOrder #[ty]): ?m.5313
``
LinearOrder: Type u β†’ Type u
LinearOrder
(← mkAppM ``LinearOrder #[ty]): ?m.5313
#[
ty: Expr
ty
(← mkAppM ``LinearOrder #[ty]): ?m.5313
])
match
linOrd: ?m.5367
linOrd
with |
some: {Ξ± : Type ?u.1204} β†’ Ξ± β†’ Option Ξ±
some
_ => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``LE.le #[e₁, eβ‚‚]): ?m.5449
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``LE.le #[e₁, eβ‚‚]): ?m.5449
``
LE.le: {Ξ± : Type u} β†’ [self : LE Ξ±] β†’ Ξ± β†’ Ξ± β†’ Prop
LE.le
(← mkAppM ``LE.le #[e₁, eβ‚‚]): ?m.5449
#[
e₁: Expr
e₁
(← mkAppM ``LE.le #[e₁, eβ‚‚]): ?m.5449
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``LE.le #[e₁, eβ‚‚]): ?m.5449
])
(← mkAppM ``not_gt_eq #[e₁, eβ‚‚]): ?m.5517
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_gt_eq #[e₁, eβ‚‚]): ?m.5517
``
not_gt_eq: βˆ€ {Ξ² : Type u} [inst : LinearOrder Ξ²] (a b : Ξ²), (Β¬a > b) = (a ≀ b)
not_gt_eq
(← mkAppM ``not_gt_eq #[e₁, eβ‚‚]): ?m.5517
#[
e₁: Expr
e₁
(← mkAppM ``not_gt_eq #[e₁, eβ‚‚]): ?m.5517
,
eβ‚‚: Expr
eβ‚‚
(← mkAppM ``not_gt_eq #[e₁, eβ‚‚]): ?m.5517
])
|
none: {Ξ± : Type ?u.1208} β†’ Option Ξ±
none
=> return
none: {Ξ± : Type ?u.5661} β†’ Option Ξ±
none
| (
``Exists: Name
``
Exists: {Ξ± : Sort u} β†’ (Ξ± β†’ Prop) β†’ Prop
Exists
, #[_,
.lam: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.lam
n: Name
n
typ: Expr
typ
bo: Expr
bo
bi]) => return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(
.forallE: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.forallE
n: Name
n
typ: Expr
typ
(
mkNot: Expr β†’ Expr
mkNot
bo: Expr
bo
) bi)
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
``
not_exists_eq: βˆ€ {Ξ± : Sort u_1} (s : Ξ± β†’ Prop), (Β¬βˆƒ x, s x) = βˆ€ (x : Ξ±), Β¬s x
not_exists_eq
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
#[
.lam: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.lam
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
n: Name
n
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
typ: Expr
typ
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
bo: Expr
bo
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
bi
(← mkAppM ``not_exists_eq #[.lam n typ bo bi]): ?m.5863
])
| (
``Exists: Name
``
Exists: {Ξ± : Sort u} β†’ (Ξ± β†’ Prop) β†’ Prop
Exists
, #[_, _]) => return
none: {Ξ± : Type ?u.6035} β†’ Option Ξ±
none
| _ => match
ex: Expr
ex
with |
.forallE: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.forallE
name: Name
name
ty: Expr
ty
body: Expr
body
binfo: BinderInfo
binfo
=> do if
(← isProp ty): ?m.6127
(←
isProp: Expr β†’ MetaM Bool
isProp
(← isProp ty): ?m.6127
ty: Expr
ty
(← isProp ty): ?m.6127
)
then return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
``
And: Prop β†’ Prop β†’ Prop
And
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
#[
ty: Expr
ty
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
,
mkNot: Expr β†’ Expr
mkNot
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
body: Expr
body
(← mkAppM ``And #[ty, mkNot body]): ?m.6264
])
(← mkAppM ``not_implies_eq #[ty, body]): ?m.6332
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_implies_eq #[ty, body]): ?m.6332
``
not_implies_eq: βˆ€ (p q : Prop), (Β¬(p β†’ q)) = (p ∧ Β¬q)
not_implies_eq
(← mkAppM ``not_implies_eq #[ty, body]): ?m.6332
#[
ty: Expr
ty
(← mkAppM ``not_implies_eq #[ty, body]): ?m.6332
,
body: Expr
body
(← mkAppM ``not_implies_eq #[ty, body]): ?m.6332
])
else let
body': Expr
body'
:
Expr: Type
Expr
:=
.lam: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.lam
name: Name
name
ty: Expr
ty
(
mkNot: Expr β†’ Expr
mkNot
body: Expr
body
)
binfo: BinderInfo
binfo
let
body'': Expr
body''
:
Expr: Type
Expr
:=
.lam: Name β†’ Expr β†’ Expr β†’ BinderInfo β†’ Expr
.lam
name: Name
name
ty: Expr
ty
body: Expr
body
binfo: BinderInfo
binfo
return
mkSimpStep: Expr β†’ Expr β†’ Simp.Step
mkSimpStep
(← mkAppM ``Exists #[body']): ?m.6510
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``Exists #[body']): ?m.6510
``
Exists: {Ξ± : Sort u} β†’ (Ξ± β†’ Prop) β†’ Prop
Exists
(← mkAppM ``Exists #[body']): ?m.6510
#[
body': Expr
body'
(← mkAppM ``Exists #[body']): ?m.6510
])
(← mkAppM ``not_forall_eq #[body'']): ?m.6576
(←
mkAppM: Name β†’ Array Expr β†’ MetaM Expr
mkAppM
(← mkAppM ``not_forall_eq #[body'']): ?m.6576
``
not_forall_eq: βˆ€ {Ξ± : Sort u_1} (s : Ξ± β†’ Prop), (Β¬βˆ€ (x : Ξ±), s x) = βˆƒ x, Β¬s x
not_forall_eq
(← mkAppM ``not_forall_eq #[body'']): ?m.6576
#[
body'': Expr
body''
(← mkAppM ``not_forall_eq #[body'']): ?m.6576
])
| _ => return
none: {Ξ± : Type ?u.6737} β†’ Option Ξ±
none
/-- Recursively push negations at the top level of the current expression. This is needed to handle e.g. triple negation. -/ partial def
transformNegation: Expr β†’ SimpM Simp.Step
transformNegation
(
e: Expr
e
:
Expr: Type
Expr
) :
SimpM: Type β†’ Type
SimpM
Simp.Step: Type
Simp.Step
:= do let
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
r₁: Simp.Result
r₁
←
transformNegationStep: Expr β†’ SimpM (Option Simp.Step)
transformNegationStep
e: Expr
e
| return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
{ expr :=
e: Expr
e
} match
r₁: Simp.Result
r₁
.
proof?: Simp.Result β†’ Option Expr
proof?
with |
none: {Ξ± : Type ?u.47269} β†’ Option Ξ±
none
=> return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
r₁: Simp.Result
r₁
|
some: {Ξ± : Type ?u.47271} β†’ Ξ± β†’ Option Ξ±
some
_ => do let
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
rβ‚‚: Simp.Result
rβ‚‚
←
transformNegation: Expr β†’ SimpM Simp.Step
transformNegation
r₁: Simp.Result
r₁
.
expr: Simp.Result β†’ Expr
expr
| return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
r₁: Simp.Result
r₁
return
Simp.Step.visit: Simp.Result β†’ Simp.Step
Simp.Step.visit
(← Simp.mkEqTrans r₁ rβ‚‚): ?m.47728
(←
Simp.mkEqTrans: Simp.Result β†’ Simp.Result β†’ MetaM Simp.Result
Simp.mkEqTrans
(← Simp.mkEqTrans r₁ rβ‚‚): ?m.47728
r₁: Simp.Result
r₁
(← Simp.mkEqTrans r₁ rβ‚‚): ?m.47728
rβ‚‚: Simp.Result
rβ‚‚
(← Simp.mkEqTrans r₁ rβ‚‚): ?m.47728
)
/-- Common entry point to `push_neg` as a conv. -/ def
pushNegCore: Expr β†’ MetaM Simp.Result
pushNegCore
(
tgt: Expr
tgt
:
Expr: Type
Expr
) :
MetaM: Type β†’ Type
MetaM
Simp.Result: Type
Simp.Result
:= do let myctx :
Simp.Context: Type
Simp.Context
:= { config := { eta :=
true: Bool
true
}, simpTheorems :=
#[ ]: Array ?m.50503
#[ ]
congrTheorems :=
(← getSimpCongrTheorems): ?m.50485
(←
getSimpCongrTheorems: MetaM SimpCongrTheorems
getSimpCongrTheorems
(← getSimpCongrTheorems): ?m.50485
)
} (Β·.1) <$>
Simp.main: Expr β†’ Simp.Context β†’ optParam Simp.UsedSimps βˆ… β†’ optParam Simp.Methods { pre := fun e => pure (Simp.Step.visit { expr := e, proof? := none, dischargeDepth := 0 }), post := fun e => pure (Simp.Step.done { expr := e, proof? := none, dischargeDepth := 0 }), discharge? := fun x => pure none } β†’ MetaM (Simp.Result Γ— Simp.UsedSimps)
Simp.main
tgt: Expr
tgt
myctx (methods := { pre :=
transformNegation: Expr β†’ SimpM Simp.Step
transformNegation
}) /-- Push negations into the conclusion of an expression. For instance, an expression `Β¬ βˆ€ x, βˆƒ y, x ≀ y` will be transformed by `push_neg` into `βˆƒ x, βˆ€ y, y < x`. Variable names are conserved. This tactic pushes negations inside expressions. For instance, given a hypothesis ```lean | Β¬ βˆ€ Ξ΅ > 0, βˆƒ Ξ΄ > 0, βˆ€ x, |x - xβ‚€| ≀ Ξ΄ β†’ |f x - yβ‚€| ≀ Ξ΅) ``` writing `push_neg` will turn the target into ```lean | βˆƒ Ξ΅, Ξ΅ > 0 ∧ βˆ€ Ξ΄, Ξ΄ > 0 β†’ (βˆƒ x, |x - xβ‚€| ≀ Ξ΄ ∧ Ξ΅ < |f x - yβ‚€|), ``` (The pretty printer does *not* use the abreviations `βˆ€ Ξ΄ > 0` and `βˆƒ Ξ΅ > 0` but this issue has nothing to do with `push_neg`). Note that names are conserved by this tactic, contrary to what would happen with `simp` using the relevant lemmas. This tactic has two modes: in standard mode, it transforms `Β¬(p ∧ q)` into `p β†’ Β¬q`, whereas in distrib mode it produces `Β¬p ∨ Β¬q`. To use distrib mode, use `set_option push_neg.use_distrib true`. -/ syntax (name :=
pushNegConv: ParserDescr
pushNegConv
) "push_neg" : conv /-- Execute `push_neg` as a conv tactic. -/ @[tactic
pushNegConv: ParserDescr
pushNegConv
] def
elabPushNegConv: Tactic
elabPushNegConv
:
Tactic: Type
Tactic
:= fun
_: ?m.52081
_
↦
withMainContext: {Ξ± : Type} β†’ TacticM Ξ± β†’ TacticM Ξ±
withMainContext
do
Conv.applySimpResult: Simp.Result β†’ TacticM Unit
Conv.applySimpResult
(← pushNegCore (← instantiateMVars (← Conv.getLhs))): ?m.52499
(←
pushNegCore: Expr β†’ MetaM Simp.Result
pushNegCore
(← pushNegCore (← instantiateMVars (← Conv.getLhs))): ?m.52499
(← instantiateMVars (← Conv.getLhs)): ?m.52293
(←
instantiateMVars: {m : Type β†’ Type} β†’ [inst : Monad m] β†’ [inst : MonadMCtx m] β†’ Expr β†’ m Expr
instantiateMVars
(← instantiateMVars (← Conv.getLhs)): ?m.52293
(← Conv.getLhs): ?m.52159
(←
Conv.getLhs: TacticM Expr
Conv.getLhs
(← Conv.getLhs): ?m.52159
)
(← instantiateMVars (← Conv.getLhs)): ?m.52293
)
(← pushNegCore (← instantiateMVars (← Conv.getLhs))): ?m.52499
)
/-- The syntax is `#push_neg e`, where `e` is an expression, which will print the `push_neg` form of `e`. `#push_neg` understands local variables, so you can use them to introduce parameters. -/ macro (name :=
pushNeg: ParserDescr
pushNeg
)
tk: ?m.53406
tk
:"#push_neg "
e: ?m.53397
e
:term : command => `(command| #conv%$
tk: ?m.53406
tk
push_neg => $
e: ?m.53397
e
) /-- Execute main loop of `push_neg` at the main goal. -/ def
pushNegTarget: TacticM Unit
pushNegTarget
:
TacticM: Type β†’ Type
TacticM
Unit: Type
Unit
:=
withMainContext: {Ξ± : Type} β†’ TacticM Ξ± β†’ TacticM Ξ±
withMainContext
do let
goal: ?m.55296
goal
←
getMainGoal: TacticM MVarId
getMainGoal
let
tgt: ?m.55636
tgt
←
instantiateMVars: {m : Type β†’ Type} β†’ [inst : Monad m] β†’ [inst : MonadMCtx m] β†’ Expr β†’ m Expr
instantiateMVars
(← goal.getType): ?m.55519
(←
goal: ?m.55296
goal
(← goal.getType): ?m.55519
.
getType: MVarId β†’ MetaM Expr
getType
(← goal.getType): ?m.55519
)
replaceMainGoal: List MVarId β†’ TacticM Unit
replaceMainGoal
[← applySimpResultToTarget goal tgt (← pushNegCore tgt)]: List ?m.55768
[←
applySimpResultToTarget: MVarId β†’ Expr β†’ Simp.Result β†’ MetaM MVarId
applySimpResultToTarget
[← applySimpResultToTarget goal tgt (← pushNegCore tgt)]: List ?m.55768
goal: ?m.55296
goal
[← applySimpResultToTarget goal tgt (← pushNegCore tgt)]: List ?m.55768
tgt: ?m.55636
tgt
[← applySimpResultToTarget goal tgt (← pushNegCore tgt)]: List ?m.55768
(← pushNegCore tgt): ?m.55690
(←
pushNegCore: Expr β†’ MetaM Simp.Result
pushNegCore
(← pushNegCore tgt): ?m.55690
tgt: ?m.55636
tgt
(← pushNegCore tgt): ?m.55690
)
[← applySimpResultToTarget goal tgt (← pushNegCore tgt)]: List ?m.55768
]
/-- Execute main loop of `push_neg` at a local hypothesis. -/ def
pushNegLocalDecl: FVarId β†’ TacticM Unit
pushNegLocalDecl
(
fvarId: FVarId
fvarId
:
FVarId: Type
FVarId
):
TacticM: Type β†’ Type
TacticM
Unit: Type
Unit
:=
withMainContext: {Ξ± : Type} β†’ TacticM Ξ± β†’ TacticM Ξ±
withMainContext
do let
ldecl: ?m.57143
ldecl
←
fvarId: FVarId
fvarId
.
getDecl: FVarId β†’ MetaM LocalDecl
getDecl
if
ldecl: ?m.57143
ldecl
.
isAuxDecl: LocalDecl β†’ Bool
isAuxDecl
then
return: ?m.57249 ?m.57251
return
let
tgt: ?m.57540
tgt
←
instantiateMVars: {m : Type β†’ Type} β†’ [inst : Monad m] β†’ [inst : MonadMCtx m] β†’ Expr β†’ m Expr
instantiateMVars
ldecl: ?m.57143
ldecl
.
type: LocalDecl β†’ Expr
type
let
goal: ?m.57588
goal
←
getMainGoal: TacticM MVarId
getMainGoal
let
myres: ?m.57642
myres
←
pushNegCore: Expr β†’ MetaM Simp.Result
pushNegCore
tgt: ?m.57540
tgt
let
some: {Ξ± : Type ?u.57737} β†’ Ξ± β†’ Option Ξ±
some
(_,
newGoal: MVarId
newGoal
) ←
applySimpResultToLocalDecl: MVarId β†’ FVarId β†’ Simp.Result β†’ Bool β†’ MetaM (Option (FVarId Γ— MVarId))
applySimpResultToLocalDecl
goal: ?m.57588
goal
fvarId: FVarId
fvarId
myres: ?m.57642
myres
False: Prop
False
|
failure: {f : Type ?u.57803 β†’ Type ?u.57802} β†’ [self : Alternative f] β†’ {Ξ± : Type ?u.57803} β†’ f Ξ±
failure
replaceMainGoal: List MVarId β†’ TacticM Unit
replaceMainGoal
[
newGoal: MVarId
newGoal
] /-- Push negations into the conclusion of a hypothesis. For instance, a hypothesis `h : Β¬ βˆ€ x, βˆƒ y, x ≀ y` will be transformed by `push_neg at h` into `h : βˆƒ x, βˆ€ y, y < x`. Variable names are conserved. This tactic pushes negations inside expressions. For instance, given a hypothesis ```lean h : Β¬ βˆ€ Ξ΅ > 0, βˆƒ Ξ΄ > 0, βˆ€ x, |x - xβ‚€| ≀ Ξ΄ β†’ |f x - yβ‚€| ≀ Ξ΅) ``` writing `push_neg at h` will turn `h` into ```lean h : βˆƒ Ξ΅, Ξ΅ > 0 ∧ βˆ€ Ξ΄, Ξ΄ > 0 β†’ (βˆƒ x, |x - xβ‚€| ≀ Ξ΄ ∧ Ξ΅ < |f x - yβ‚€|), ``` (The pretty printer does *not* use the abreviations `βˆ€ Ξ΄ > 0` and `βˆƒ Ξ΅ > 0` but this issue has nothing to do with `push_neg`). Note that names are conserved by this tactic, contrary to what would happen with `simp` using the relevant lemmas. One can also use this tactic at the goal using `push_neg`, at every hypothesis and the goal using `push_neg at *` or at selected hypotheses and the goal using say `push_neg at h h' ⊒` as usual. This tactic has two modes: in standard mode, it transforms `Β¬(p ∧ q)` into `p β†’ Β¬q`, whereas in distrib mode it produces `Β¬p ∨ Β¬q`. To use distrib mode, use `set_option push_neg.use_distrib true`. -/ elab "push_neg"
loc: ?m.60488
loc
:(
ppSpace: Parser.Parser
ppSpace
location: ParserDescr
location
)? : tactic => let
loc: ?m.60507
loc
:= (
loc: ?m.60488
loc
.
map: {Ξ± : Type ?u.60509} β†’ {Ξ² : Type ?u.60508} β†’ (Ξ± β†’ Ξ²) β†’ Option Ξ± β†’ Option Ξ²
map
expandLocation: Syntax β†’ Location
expandLocation
).
getD: {Ξ± : Type ?u.60666} β†’ Option Ξ± β†’ Ξ± β†’ Ξ±
getD
(
.targets: Array Syntax β†’ Bool β†’ Location
.targets
#[]: Array ?m.60672
#[]
true: Bool
true
)
withLocation: Location β†’ (FVarId β†’ TacticM Unit) β†’ TacticM Unit β†’ (MVarId β†’ TacticM Unit) β†’ TacticM Unit
withLocation
loc: ?m.60507
loc
pushNegLocalDecl: FVarId β†’ TacticM Unit
pushNegLocalDecl
pushNegTarget: TacticM Unit
pushNegTarget
(fun
_: ?m.60706
_
↦
logInfo: {m : Type β†’ Type} β†’ [inst : Monad m] β†’ [inst : MonadLog m] β†’ [inst : AddMessageContext m] β†’ [inst : MonadOptions m] β†’ MessageData β†’ m Unit
logInfo
"push_neg couldn't find a negation to push": String
"push_neg couldn't find a negation to push"
)