Zulip Chat Archive

Stream: lean4

Topic: Overlapping four-place notation


𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Sep 06 2024 at 19:36):

Hi! I am trying to introduce a notation which partially overlaps with (modN)\pmod N notation from mathlib. It works in one variant, and not in another. Does anybody understand why this is happening?

import Mathlib.Data.Nat.ModEq

#check 1  5 [MOD 4] -- 1 ≡ 5 [MOD 4] : Prop

notation:50 x " ≡ " y " [AMOD " N "]" => N
#check 1  2 [AMOD 3] -- 3 : ℕ

notation:50 a " ∣ " b " ≡ " c " [BMOD " N "]" => N
#check 1  2  3 [BMOD 4] -- unexpected token '[BMOD'; expected '[AMOD' or '[MOD'

Sebastian Ullrich (Sep 06 2024 at 19:56):

You'll probably want to increase the precedence of a so that it doesn't capture all of 1 | 2 as a single term

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Sep 08 2024 at 01:50):

I used a Unicode to avoid clashing with |. Increasing the precedence does not seem to change anything.

Kyle Miller (Sep 08 2024 at 01:56):

Here's the incantation:

notation:50 a:51 " ∣ " b:51 " ≡ " c " [BMOD " N "]" => N

You have to match the precedences that the infix command sets for the operator

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Sep 11 2024 at 01:00):

Thank you! Are you sure this is about the precedence of the operator? Using a symbol which is certainly not an infix operator fails in the same way:

notation:50 a " ✨ " b " ≡ " c " [BMOD " N "]" => N
#check 1  2  3 [BMOD 4] -- unexpected token '[BMOD'; expected '[AMOD' or '[MOD'

but with notation:50 a " ✨ " b:51 " ≡ " c " [BMOD " N "]" => N, it works. So I am led to conclude that without the extra precedence, it is being parsed as 1 ✨ (2 ≡ 3 [BMOD 4]). The mod notations from mathlib also have precedence 50.

Sebastian Ullrich (Sep 11 2024 at 09:50):

I think you're right, b's precedence is the one that matters

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Sep 11 2024 at 16:36):

Is there anything I could read to better understand the Pratt parsing rules of Lean? This article is nice but it doesn't account for the feature of "output precedences" syntax:$prec that Lean has.

Sebastian Ullrich (Sep 11 2024 at 16:39):

The new manual is in progress but does this help in the meantime? I wouldn't think about it on the Pratt algorithm level but as a combination of the placeholder and longest parse rules mentioned there

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Sep 11 2024 at 23:46):

Ahh, not really. "Local longest parse" isn't precise enough for me to predict or understand what would happen in situations like the one above. I mean, 1 ∣ 2 ≡ 3 [BMOD 4] is a longer parse than 1 ∣ (2 ≡ 3 <error>), I think? But maybe the "local" part implies that once we start parsing the nested b:term and see something that _could_ be 2 ≡ 3 [MOD .., we'll commit to that and hence the error occurs? Overall, a precise description would be preferable (but I understand it's not super high priority to explain the weeds).


Last updated: May 02 2025 at 03:31 UTC