Zulip Chat Archive

Stream: lean4

Topic: Defining my own numerals


Brandon Brown (Apr 29 2021 at 02:26):

I've defined my own nat type in the usual way:

inductive nat where
  | zero : nat
  | succ : nat  nat

And I want to somehow represent the repeated function composition e.g. nat.succ (nat.succ (nat.zero)) as a unary numeral system like 11111 (or some other arbitrary unicode character). How could I go about doing this in Lean4? Eventually I'd like to map this into a binary system again with my own non-standard numerals.

Mario Carneiro (Apr 29 2021 at 02:56):

You could make 1 or its unicode replacement a prefix operator, although you would need a 0 at the end to finish it off

Brandon Brown (Apr 29 2021 at 03:11):

That's clever, thanks. It's definitely more pleasant to look at that nat.succ. Is there a way to similarly map a custom notation to a term too like the infix/prefix command does for functions?

Brandon Brown (Apr 29 2021 at 03:13):

I can just define a new term like def c := nat.zero but it doesn't let me use arbitrary unicode, and it doesn't show up in the result of #reduce

Brandon Brown (Apr 29 2021 at 03:19):

Figured it out from looking at the Lean4 "lean4/src/Init/Notation.lean": I can use this notation:max "₀" => nat.zero

Brandon Brown (Apr 29 2021 at 03:22):

Although if I want to use the regular 0 numeral the default implementation cannot be overridden by setting the priority notation:max (priority := high) "0" => nat.zero
error: failed to synthesize instance OfNat nat 0

Mario Carneiro (Apr 29 2021 at 03:28):

I don't think you have to override the syntax for 0 if you just want to use 0; just implement OfNat nat 0

Daniel Selsam (Apr 29 2021 at 03:44):

This isn't pretty but here is one approach:

inductive nat where
  | zero : nat
  | succ : nat  nat

prefix "I|" => nat.succ
instance : OfNat nat (nat_lit 0) := nat.zero

example : nat.succ (nat.succ (nat.succ nat.zero)) = I|I|I|0 := rfl

You might need to write a custom parser to support notation like m111 for 3, similar to the builtin parser for hex.

Mario Carneiro (Apr 29 2021 at 04:03):

if you use a non-identifier token it should be lexed as a sequence even if there are no spaces

Mario Carneiro (Apr 29 2021 at 04:04):

prefix "🅂" => nat.succ
instance : OfNat nat (nat_lit 0) := nat.zero

example : nat.succ (nat.succ (nat.succ nat.zero)) = 🅂🅂🅂0 := rfl

Mario Carneiro (Apr 29 2021 at 04:06):

in lean 3 there was the ability to declare an identifier sequence as a token even if it is alphanumeric, using the precedence command. Does this still exist in lean 4?

Mario Carneiro (Apr 29 2021 at 04:09):

actually I take it back, you still need spaces around identifier tokens (except #print for some reason)

#printnat
-- inductive nat : Type
-- constructors:
-- nat.zero : nat
-- nat.succ : nat → nat

Brandon Brown (Apr 29 2021 at 04:16):

Thanks both.

local notation:max "z" => nat.zero
local prefix:max "s" => nat.succ
#reduce (s s s z) + (s s z) -- s s s s s z

Is fine for now until I figure out how to build a custom parser, which I may never do realistically hah

Brandon Brown (Apr 29 2021 at 04:54):

This also helps at least with printing.

def nat2str : nat  String :=
  fun
  | nat.zero => ""
  | nat.succ a => "1" ++ nat2str a

#eval nat2str (s s s z) -- "111"

instance : ToString nat where
  toString : nat  String := nat2str

#eval (s s s z) + (s s z) -- 11111

François G. Dorais (Apr 29 2021 at 07:40):

A slightly different variant:

instance : OfNat nat (nat_lit 0) := zero

postfix:max "⁺" => succ

#reduce (succ (succ (succ zero))) -- zero⁺⁺⁺

instance : Repr nat :=
  let rec repr : nat  String
  | zero => "0"
  | succ n => repr n ++ "⁺"
  fun n _ => repr n

#eval (succ (succ (succ zero))) -- 0⁺⁺⁺

def add : nat  nat  nat
| x, 0 => x
| x, y => (add x y)

instance : Add nat := add

example : 0⁺⁺⁺ + 0⁺⁺ = 0⁺⁺⁺⁺⁺ := rfl

Sebastian Ullrich (Apr 29 2021 at 07:55):

notation:max "🍎" => succ zero
prefix:max "🍎"   => succ

example : 🍎🍎🍎 + 🍎🍎 = 🍎🍎🍎🍎🍎 := rfl

Kevin Buzzard (Apr 29 2021 at 12:08):

I'm so adding this to my school talks


Last updated: Dec 20 2023 at 11:08 UTC