-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
import Mathlib.Tactic
set_option warningAsError false
namespace PiNotation
open Lean.Parser Term
open Lean.PrettyPrinter.Delaborator
/-- Dependent function type (a "pi type"). The notation `Π x : α, β x` can
also be written as `(x : α) → β x`. -/
-- A direct copy of forall notation but with `Π`/`Pi` instead of `∀`/`Forall`.
@[term_parser]
def piNotation := leading_parser:leadPrec
unicodeSymbol "Π" "Pi" >>
many1 (ppSpace >> (binderIdent <|> bracketedBinder)) >>
optType >> ", " >> termParser
/-- Dependent function type (a "pi type"). The notation `Π x ∈ s, β x` is
short for `Π x, x ∈ s → β x`. -/
-- A copy of forall notation from `Std.Util.ExtendedBinder` for pi notation
syntax "Π " binderIdent binderPred ", " term : term
macro_rules
| `(Π $x:ident $pred:binderPred, $p) =>
`(Π $x:ident, satisfies_binder_pred% $x $pred → $p)
| `(Π _ $pred:binderPred, $p) =>
`(Π x, satisfies_binder_pred% x $pred → $p)
/-- Since pi notation and forall notation are interchangable, we can
parse it by simply using the forall parser. -/
@[macro PiNotation.piNotation] def replacePiNotation : Lean.Macro
| .node info _ args => return .node info ``Lean.Parser.Term.forall args
| _ => Lean.Macro.throwUnsupported
/-- Override the Lean 4 pi notation delaborator with one that uses `Π`.
Note that this takes advantage of the fact that `(x : α) → p x` notation is
never used for propositions, so we can match on this result and rewrite it. -/
@[delab forallE]
def delabPi : Delab := whenPPOption Lean.getPPNotation do
let stx ← delabForall
-- Replacements
let stx : Term ←
match stx with
| `($group:bracketedBinder → $body) => `(Π $group:bracketedBinder, $body)
| _ => pure stx
-- Cute binders
let stx : Term ←
match stx with
| `(∀ ($i:ident : $_), $j:ident ∈ $s → $body) =>
if i == j then `(∀ $i:ident ∈ $s, $body) else pure stx
| `(∀ ($x:ident : $_), $y:ident > $z → $body) =>
if x == y then `(∀ $x:ident > $z, $body) else pure stx
| `(∀ ($x:ident : $_), $y:ident < $z → $body) =>
if x == y then `(∀ $x:ident < $z, $body) else pure stx
| `(∀ ($x:ident : $_), $y:ident ≥ $z → $body) =>
if x == y then `(∀ $x:ident ≥ $z, $body) else pure stx
| `(∀ ($x:ident : $_), $y:ident ≤ $z → $body) =>
if x == y then `(∀ $x:ident ≤ $z, $body) else pure stx
| `(Π ($i:ident : $_), $j:ident ∈ $s → $body) =>
if i == j then `(Π $i:ident ∈ $s, $body) else pure stx
| _ => pure stx
-- Merging
match stx with
| `(Π $group, Π $groups*, $body) => `(Π $group $groups*, $body)
| _ => pure stx
-- the above delaborator and parser are still needed:
-- #check Π (x : Nat), Vector Bool x
end PiNotation
section SupInfNotation
open Lean Lean.PrettyPrinter.Delaborator
/-!
Improvements to the unexpanders in `Mathlib.Order.CompleteLattice`.
These are implemented as delaborators directly.
-/
@[delab app.iSup]
def iSup_delab : Delab := whenPPOption Lean.getPPNotation do
let #[_, _, ι, f] := (← SubExpr.getExpr).getAppArgs | failure
unless f.isLambda do failure
let prop ← Meta.isProp ι
let dep := f.bindingBody!.hasLooseBVar 0
let ppTypes ← getPPOption getPPFunBinderTypes
let stx ← SubExpr.withAppArg do
let dom ← SubExpr.withBindingDomain delab
withBindingBodyUnusedName $ fun x => do
let x : TSyntax `ident := .mk x
let body ← delab
if prop && !dep then
`(⨆ (_ : $dom), $body)
else if prop || ppTypes then
`(⨆ ($x:ident : $dom), $body)
else
`(⨆ $x:ident, $body)
-- Cute binders
let stx : Term ←
match stx with
| `(⨆ $x:ident, ⨆ (_ : $y:ident ∈ $s), $body)
| `(⨆ ($x:ident : $_), ⨆ (_ : $y:ident ∈ $s), $body) =>
if x == y then `(⨆ $x:ident ∈ $s, $body) else pure stx
| _ => pure stx
return stx
@[delab app.infᵢ]
def infᵢ_delab : Delab := whenPPOption Lean.getPPNotation do
let #[_, _, ι, f] := (← SubExpr.getExpr).getAppArgs | failure
unless f.isLambda do failure
let prop ← Meta.isProp ι
let dep := f.bindingBody!.hasLooseBVar 0
let ppTypes ← getPPOption getPPFunBinderTypes
let stx ← SubExpr.withAppArg do
let dom ← SubExpr.withBindingDomain delab
withBindingBodyUnusedName $ fun x => do
let x : TSyntax `ident := .mk x
let body ← delab
if prop && !dep then
`(⨅ (_ : $dom), $body)
else if prop || ppTypes then
`(⨅ ($x:ident : $dom), $body)
else
`(⨅ $x:ident, $body)
-- Cute binders
let stx : Term ←
match stx with
| `(⨅ $x:ident, ⨅ (_ : $y:ident ∈ $s), $body)
| `(⨅ ($x:ident : $_), ⨅ (_ : $y:ident ∈ $s), $body) =>
if x == y then `(⨅ $x:ident ∈ $s, $body) else pure stx
| _ => pure stx
return stx
/-- The Exists notation has similar considerations as sup/inf -/
@[delab app.Exists]
def exists_delab : Delab := whenPPOption Lean.getPPNotation do
let #[ι, f] := (← SubExpr.getExpr).getAppArgs | failure
unless f.isLambda do failure
let prop ← Meta.isProp ι
let dep := f.bindingBody!.hasLooseBVar 0
let ppTypes ← getPPOption getPPFunBinderTypes
let stx ← SubExpr.withAppArg do
let dom ← SubExpr.withBindingDomain delab
withBindingBodyUnusedName $ fun x => do
let x : TSyntax `ident := .mk x
let body ← delab
if prop && !dep then
`(∃ (_ : $dom), $body)
else if prop || ppTypes then
`(∃ ($x:ident : $dom), $body)
else
`(∃ $x:ident, $body)
-- Cute binders
let stx : Term ←
match stx with
| `(∃ $i:ident, $j:ident ∈ $s ∧ $body)
| `(∃ ($i:ident : $_), $j:ident ∈ $s ∧ $body) =>
if i == j then `(∃ $i:ident ∈ $s, $body) else pure stx
| `(∃ $x:ident, $y:ident > $z ∧ $body)
| `(∃ ($x:ident : $_), $y:ident > $z ∧ $body) =>
if x == y then `(∃ $x:ident > $z, $body) else pure stx
| `(∃ $x:ident, $y:ident < $z ∧ $body)
| `(∃ ($x:ident : $_), $y:ident < $z ∧ $body) =>
if x == y then `(∃ $x:ident < $z, $body) else pure stx
| `(∃ $x:ident, $y:ident ≥ $z ∧ $body)
| `(∃ ($x:ident : $_), $y:ident ≥ $z ∧ $body) =>
if x == y then `(∃ $x:ident ≥ $z, $body) else pure stx
| `(∃ $x:ident, $y:ident ≤ $z ∧ $body)
| `(∃ ($x:ident : $_), $y:ident ≤ $z ∧ $body) =>
if x == y then `(∃ $x:ident ≤ $z, $body) else pure stx
| _ => pure stx
-- Merging
match stx with
| `(∃ $group:bracketedExplicitBinders, ∃ $groups*, $body) => `(∃ $group $groups*, $body)
| _ => pure stx
-- the above delaborators are still needed:
-- #check ⨆ (i : Nat) (_ : i ∈ Set.univ), (i = i)
-- #check ∃ (i : Nat), i ≥ 3 ∧ i = i
end SupInfNotation
section UnionInterNotation
open Lean Lean.PrettyPrinter.Delaborator
/-!
Improvements to the unexpanders in `Mathlib.Data.Set.Lattice`.
These are implemented as delaborators directly.
-/
@[delab app.Set.unionᵢ]
def unionᵢ_delab : Delab := whenPPOption Lean.getPPNotation do
let #[_, ι, f] := (← SubExpr.getExpr).getAppArgs | failure
unless f.isLambda do failure
let prop ← Meta.isProp ι
let dep := f.bindingBody!.hasLooseBVar 0
let ppTypes ← getPPOption getPPFunBinderTypes
let stx ← SubExpr.withAppArg do
let dom ← SubExpr.withBindingDomain delab
withBindingBodyUnusedName $ fun x => do
let x : TSyntax `ident := .mk x
let body ← delab
if prop && !dep then
`(⋃ (_ : $dom), $body)
else if prop || ppTypes then
`(⋃ ($x:ident : $dom), $body)
else
`(⋃ $x:ident, $body)
-- Cute binders
let stx : Term ←
match stx with
| `(⋃ $x:ident, ⋃ (_ : $y:ident ∈ $s), $body)
| `(⋃ ($x:ident : $_), ⋃ (_ : $y:ident ∈ $s), $body) =>
if x == y then `(⋃ $x:ident ∈ $s, $body) else pure stx
| _ => pure stx
return stx
@[delab app.Set.interᵢ]
def interᵢ_delab : Delab := whenPPOption Lean.getPPNotation do
let #[_, ι, f] := (← SubExpr.getExpr).getAppArgs | failure
unless f.isLambda do failure
let prop ← Meta.isProp ι
let dep := f.bindingBody!.hasLooseBVar 0
let ppTypes ← getPPOption getPPFunBinderTypes
let stx ← SubExpr.withAppArg do
let dom ← SubExpr.withBindingDomain delab
withBindingBodyUnusedName $ fun x => do
let x : TSyntax `ident := .mk x
let body ← delab
if prop && !dep then
`(⋂ (_ : $dom), $body)
else if prop || ppTypes then
`(⋂ ($x:ident : $dom), $body)
else
`(⋂ $x:ident, $body)
-- Cute binders
let stx : Term ←
match stx with
| `(⋂ $x:ident, ⋂ (_ : $y:ident ∈ $s), $body)
| `(⋂ ($x:ident : $_), ⋂ (_ : $y:ident ∈ $s), $body) =>
if x == y then `(⋂ $x:ident ∈ $s, $body) else pure stx
| _ => pure stx
return stx
-- the above delaborators might not work correctly
-- #check ⋃ (s : Set ℕ) (_ : s ∈ Set.univ), s
end UnionInterNotation
namespace ProdProjNotation
open Lean Lean.PrettyPrinter.Delaborator
@[delab app.Prod.fst, delab app.Prod.snd]
def delabProdProjs : Delab := do
let #[_, _, _] := (← SubExpr.getExpr).getAppArgs | failure
let stx ← delabProjectionApp
match stx with
| `($(x).fst) => `($(x).1)
| `($(x).snd) => `($(x).2)
| _ => failure
/-! That works when the projection is a simple term, but we need
another approach when the projections are functions with applied arguments. -/
@[app_unexpander Prod.fst]
def unexpandProdFst : Lean.PrettyPrinter.Unexpander
| `($(_) $p $xs*) => `($p.1 $xs*)
| _ => throw ()
@[app_unexpander Prod.snd]
def unexpandProdSnd : Lean.PrettyPrinter.Unexpander
| `($(_) $p $xs*) => `($p.2 $xs*)
| _ => throw ()
example (p : Nat × Nat) : p.1 = p.2 → True := by simp
example (p : (Nat → Nat) × (Nat → Nat)) : p.1 22 = p.2 37 → True := by simp
end ProdProjNotation