Zulip Chat Archive

Stream: lean4

Topic: notation doesn't work with implicit arguments


Junyan Xu (May 21 2024 at 06:08):

Is it possible to specify an implicit argument in a notation without preventing the notation from being displayed? In the following snippet, the notations fin2 and fin3 parse correctly but doesn't display as intended.

notation "fin1" => Fin 1
notation "fin2" => @Fin 2
notation "fin3" => Fin (n := 3)

example : fin1 = fin2  fin2 = fin3 := by
  /- unsolved goals
⊢ fin1 = Fin 2 ∧ Fin 2 = Fin 3 -/

In this case n is actually explicit in Fin n so we can just use fin1, but when we have a def with an implicit argument to start with, for example docs#Polynomial.X, I have to make an abbrev Polynomial.X' (R) [Semiring R] := Polynomial.X (R := R) and do notation "Y" => Polynomial.X' (Polynomial _) etc. (to distinguish the two variables in R[X][X]).

When diagnosing this problem I discovered this example that may offer some hints:

notation "idN" => id Nat

#check idN -- idN : Type

notation "ℕ" => Nat

#check idN -- id ℕ : Type

notation "idN1" => id 

#check idN1   -- idN1 : Type
#check idN    -- idN1 : Type
#check id Nat -- idN1 : Type
#check id    -- idN1 : Type

In short, if Nat is given a notation, then a notation involving something applied to Nat will not display, and you have to use Nat's notation to define subsequent notations involving Nat. In the second #check idN, it seems that the pretty printer does one step (replace Nat by ℕ) and then stops. I wonder whether what's happening with the notations with implicit argument is also that the pretty printer sees @Fin 2 or Fin (n := 3), replaces it with Fin 2 or Fin 3 and then stops, without going further to replace them by fin2 or fin3.

It has to be something applied to Nat instead of Nat alone though: if you just give Nat a new notation it will just work:

notation "N" => Nat
#check N -- N : Type

notation "N1" => Nat
#check N1 -- N1 : Type
#check N  -- N1 : Type

I appreciate your input and diagnosis on this issue.

Junyan Xu (May 21 2024 at 16:21):

(deleted)

Kyle Miller (May 21 2024 at 17:28):

The pretty printer generator for notation is fairly simple. Your first example is completely explained by the following observation:

notation "fin1" => Fin 1 -- generates a pretty printer
notation "fin2" => @Fin 2 -- does not generate a pretty printer
notation "fin3" => Fin (n := 3) -- does not generate a pretty printer

I have been planning on adding a warning message to notation when it does not succeed in generating a pretty printer, along with an option to acknowledge the warning. For example, it might look like notation (prettyPrinter := false) "fin2" => @Fin 2 to turn off the warning.

Kyle Miller (May 21 2024 at 17:32):

For the Nat examples, the sorts of pretty printers that notation generates (app unexpanders) are evaluated "inside-out". That is, leaves-first root-last. Also, the last app unexpander to be defined is the one that takes precedence. This explains why idN1 applies in each case, if you add in the fact that app unexpanders operate by matching syntax, hence why it works only because is in the RHS pattern.

Kyle Miller (May 21 2024 at 17:33):

If you are using mathlib, you can use notation3, which creates delaborators instead of app unexpanders. The delaborators it generates additionally operate "outside-in".

Kyle Miller (May 21 2024 at 17:34):

There are some thoughts about making notation generate delaborators as well

Junyan Xu (May 21 2024 at 17:41):

Thanks! notation3 seems to work with my intended application to Polynomial. I recall the notation Y also had issues back in mathlib3, but maybe notation3 fixed those :)

Kyle Miller (May 21 2024 at 17:51):

Let me know what you find!

Junyan Xu (May 21 2024 at 20:52):

The only place I find the notation3 doesn't work perfectly is:

import Mathlib.Algebra.Polynomial.Basic
notation3 "Y" => Polynomial.X (R := Polynomial _)
open Polynomial
variable (R : Type*) [Ring R]
noncomputable section
example : R[X][X] := -Y -- failed to synthesize instance Neg ?m.2233[X][X]
example : R[X][X] := Y -- works
example : R[X][X] := Y + C X -- works
example : R[X][X] := -(Y : R[X][X]) -- works
example : R[X][X] := -X -- works

Last updated: May 02 2025 at 03:31 UTC