Skip to content

Commit dc65f03

Browse files
authored
feat: PProd and MProd syntax (part 1) (#4747)
the internal constructions for structural and well-founded recursion use plenty of `PProd` and `MProd`, and reading these, deeply nested and in prefix notation, is unnecessarily troublesome. Therefore this introduces notations ``` a ×ₚ b -- PProd a b a ×ₘ b -- MProd a b ()ₚ -- PUnit.unit (x,y,z)ₚ -- PProd.mk x (PProd.mk y z) (x,y,z)ₘ -- MProd.mk x (MProd.mk y z) ``` (This is part 1, the rest will follow in #4730 after a stage0 update.)
1 parent de96b6d commit dc65f03

8 files changed

+65
-4
lines changed

src/Init/Notation.lean

+2
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ syntax (name := rawNatLit) "nat_lit " num : term
267267

268268
@[inherit_doc] infixr:90 " ∘ " => Function.comp
269269
@[inherit_doc] infixr:35 " × " => Prod
270+
@[inherit_doc] infixr:35 " ×ₚ " => PProd
271+
@[inherit_doc] infixr:35 " ×ₘ " => MProd
270272

271273
@[inherit_doc] infix:50 " ∣ " => Dvd.dvd
272274
@[inherit_doc] infixl:55 " ||| " => HOr.hOr

src/Init/NotationExtra.lean

+12
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ end Lean
163163
| `($(_) $x $y) => `(($x, $y))
164164
| _ => throw ()
165165

166+
/-
167+
@[app_unexpander PProd.mk] def unexpandPProdMk : Lean.PrettyPrinter.Unexpander
168+
| `($(_) $x ($y, $ys,*)ₚ) => `(($x, $y, $ys,*)ₚ)
169+
| `($(_) $x $y) => `(($x, $y)ₚ)
170+
| _ => throw ()
171+
172+
@[app_unexpander MProd.mk] def unexpandMProdMk : Lean.PrettyPrinter.Unexpander
173+
| `($(_) $x ($y, $ys,*)ₘ) => `(($x, $y, $ys,*)ₘ)
174+
| `($(_) $x $y) => `(($x, $y)ₘ)
175+
| _ => throw ()
176+
-/
177+
166178
@[app_unexpander ite] def unexpandIte : Lean.PrettyPrinter.Unexpander
167179
| `($(_) $c $t $e) => `(if $c then $t else $e)
168180
| _ => throw ()

src/Lean/Elab/BuiltinNotation.lean

+36
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,31 @@ partial def mkPairs (elems : Array Term) : MacroM Term :=
220220
pure acc
221221
loop (elems.size - 1) elems.back
222222

223+
/-- Return syntax `PProd.mk elems[0] (PProd.mk elems[1] ... (PProd.mk elems[elems.size - 2] elems[elems.size - 1])))` -/
224+
partial def mkPPairs (elems : Array Term) : MacroM Term :=
225+
let rec loop (i : Nat) (acc : Term) := do
226+
if i > 0 then
227+
let i := i - 1
228+
let elem := elems[i]!
229+
let acc ← `(PProd.mk $elem $acc)
230+
loop i acc
231+
else
232+
pure acc
233+
loop (elems.size - 1) elems.back
234+
235+
/-- Return syntax `MProd.mk elems[0] (MProd.mk elems[1] ... (MProd.mk elems[elems.size - 2] elems[elems.size - 1])))` -/
236+
partial def mkMPairs (elems : Array Term) : MacroM Term :=
237+
let rec loop (i : Nat) (acc : Term) := do
238+
if i > 0 then
239+
let i := i - 1
240+
let elem := elems[i]!
241+
let acc ← `(MProd.mk $elem $acc)
242+
loop i acc
243+
else
244+
pure acc
245+
loop (elems.size - 1) elems.back
246+
247+
223248
open Parser in
224249
partial def hasCDot : Syntax → Bool
225250
| Syntax.node _ k args =>
@@ -305,6 +330,17 @@ where
305330
return (← expandCDot? pairs).getD pairs
306331
| _ => Macro.throwUnsupported
307332

333+
/-
334+
@[builtin_macro Lean.Parser.Term.ptuple] def expandPTuple : Macro
335+
| `(()ₚ) => ``(PUnit.unit)
336+
| `(($e, $es,*)ₚ) => mkPPairs (#[e] ++ es)
337+
| _ => Macro.throwUnsupported
338+
339+
@[builtin_macro Lean.Parser.Term.mtuple] def expandMTuple : Macro
340+
| `(($e, $es,*)ₘ) => mkMPairs (#[e] ++ es)
341+
| _ => Macro.throwUnsupported
342+
-/
343+
308344
@[builtin_macro Lean.Parser.Term.typeAscription] def expandTypeAscription : Macro
309345
| `(($e : $(type)?)) => do
310346
match (← expandCDot? e) with

src/Lean/Parser/Term.lean

+10
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,19 @@ do not yield the right result.
174174
-/
175175
@[builtin_term_parser] def typeAscription := leading_parser
176176
"(" >> (withoutPosition (withoutForbidden (termParser >> " :" >> optional (ppSpace >> termParser)))) >> ")"
177+
177178
/-- Tuple notation; `()` is short for `Unit.unit`, `(a, b, c)` for `Prod.mk a (Prod.mk b c)`, etc. -/
178179
@[builtin_term_parser] def tuple := leading_parser
179180
"(" >> optional (withoutPosition (withoutForbidden (termParser >> ", " >> sepBy1 termParser ", " (allowTrailingSep := true)))) >> ")"
181+
182+
/-- Universe polymorphic tuple notation; `()ₚ` is short for `PUnit.unit`, `(a, b, c)ₚ` for `PProd.mk a (PProd.mk b c)`, etc. -/
183+
@[builtin_term_parser] def ptuple := leading_parser
184+
"(" >> optional (withoutPosition (withoutForbidden (termParser >> ", " >> sepBy1 termParser ", " (allowTrailingSep := true)))) >> ")ₚ"
185+
186+
/-- Universe monomorphic tuple notation; `(a, b, c)ₘ` for `MProd.mk a (MProd.mk b c)`, etc. -/
187+
@[builtin_term_parser] def mtuple := leading_parser
188+
"(" >> withoutPosition (withoutForbidden (termParser >> ", " >> sepBy1 termParser ", " (allowTrailingSep := true))) >> ")ₘ"
189+
180190
/--
181191
Parentheses, used for grouping expressions (e.g., `a * (b + c)`).
182192
Can also be used for creating simple functions when combined with `·`. Here are some examples:

stage0/src/stdlib_flags.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ options get_default_options() {
88
// switch to `true` for ABI-breaking changes affecting meta code
99
opts = opts.update({"interpreter", "prefer_native"}, false);
1010
// switch to `true` for changing built-in parsers used in quotations
11-
opts = opts.update({"internal", "parseQuotWithCurrentStage"}, false);
11+
opts = opts.update({"internal", "parseQuotWithCurrentStage"}, true);
1212
// toggling `parseQuotWithCurrentStage` may also require toggling the following option if macros/syntax
1313
// with custom precheck hooks were affected
1414
opts = opts.update({"quotPrecheck"}, true);

tests/lean/348.lean.expected.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
348.lean:3:24-3:25: error: unexpected token '⟩'; expected ')'
1+
348.lean:3:24-3:25: error: unexpected token '⟩'; expected ')', ')ₘ' or ')ₚ'

tests/lean/interactive/incrementalTactic.lean.expected.out

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ t 2
3232
"severity": 1,
3333
"range":
3434
{"start": {"line": 1, "character": 38}, "end": {"line": 4, "character": 3}},
35-
"message": "unexpected token '/-!'; expected ')', '_', identifier or term",
35+
"message":
36+
"unexpected token '/-!'; expected ')', ')ₚ', '_', identifier or term",
3637
"fullRange":
3738
{"start": {"line": 1, "character": 38},
3839
"end": {"line": 4, "character": 3}}}]}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[1, 2, 3]
22
(2, 3)
33
trailingComma.lean:6:13-6:14: error: unexpected token ','; expected ']'
4-
trailingComma.lean:7:11-7:12: error: unexpected token ','; expected ')'
4+
trailingComma.lean:7:11-7:12: error: unexpected token ','; expected ')', ')ₘ' or ')ₚ'

0 commit comments

Comments
 (0)