Zulip Chat Archive

Stream: new members

Topic: Most conventional way to match nonzero natural numbers


Plamen Dimitrov (Apr 29 2025 at 07:26):

Hi all, I had to come up with this termination proof for conversion to binary numbers

def ofNat : Nat  Binary
| n => (ofNatReversed n).reverse
where
  ofNatReversed : Nat  Binary
  | .zero => []
  | .succ n => (if (.succ n) % 2 == 0 then Bit.zero else Bit.one) :: ofNatReversed ((.succ n) / 2)
  termination_by n => n
  decreasing_by
    apply Nat.div_lt_self
    · apply Nat.pos_of_ne_zero
      intro h
      contradiction
    · decide

where the proof would require that n \ne 0 in the recursive case if I were to perform a simpler matching like

 ofNatReversed : Nat  Binary
  | 0 => []
  | n => (if n % 2 == 0 then Bit.zero else Bit.one) :: ofNatReversed (n / 2)

I would like to have something simpler like this but the problem is that n would also match zero as a natural number and the terminal proof cannot proceed. Lean is not aware of any order of matching to conclude that when we match n we would have already matched 0 before if ever and thus n should not be zero. Is there a better established way to match nonzero natural numbers or a more conventional way to do this terminal proof using only the simpler n match?

Robin Arnez (Apr 29 2025 at 08:02):

just do

inductive Bit where
  | zero | one

def Binary := List Bit

def ofNat : Nat  Binary
| n => (ofNatReversed n).reverse
where
  ofNatReversed (n : Nat) : Binary :=
    if n = 0 then []
    else
      (if n % 2 = 0 then Bit.zero else Bit.one) :: ofNatReversed (n / 2)

Plamen Dimitrov (Apr 29 2025 at 16:26):

Hi @Robin, I thought about the if-else-then function but matching a constructor seems more natural to me as something I would prefer to use. Do you think there is any way this can be achieved using the more inductive-type-friendly matching approach?


Last updated: May 02 2025 at 03:31 UTC