Zulip Chat Archive

Stream: new members

Topic: axiomatize natural numbers


Yusuke Inoue (Jun 30 2025 at 09:45):

I tried to define a type class to represent Peano axioms.

class PeanoAxioms (N : Type) extends Zero N where
  succ : N -> N
  zeroNoSucc : n : N, ¬ succ n = 0
  succCancel : a b : N, succ a = succ b  a = b
  induction : f : N  Sort*, f 0  (n : N, f n  f (succ n))  n : N, f n

postfix:100 "++" => PeanoAxioms.succ

I use Sort* here because (at least so far) I don't think proof irrelevance is a good idea.

However, it seems that computing on the abstract natural numbers is impossible (take the following as an example).

namespace PeanoAxioms

variable {N : Type}[PeanoAxioms N]

theorem conv0 {f : N  Sort*} (base : f 0) (succ : n : N, f n  f (n++)) : induction f base succ 0 = base := by sorry

But for any instance of the type class, the computing process seems always possible.

What's wrong?

Kenny Lau (Jun 30 2025 at 09:48):

It's working as intended :upside_down:

When you axiomatise something you're just requiring a type (+structure) to satisfy those extra rules. there's certainly no requirements that those equalities should be defeq.

Maybe this is where your confusion is. Lean's defeq is not mathematician's defeq!

Kenny Lau (Jun 30 2025 at 09:50):

btw please add import Mathlib so that your code compiles; and actually I'm confused here, what do you mean that it's impossible? you just added by sorry to your code, I don't know what that's supposed to mean.

Kenny Lau (Jun 30 2025 at 09:50):

Can you explain what you mean by "impossible"?

Yusuke Inoue (Jun 30 2025 at 09:53):

Kenny Lau said:

btw please add import Mathlib so that your code compiles; and actually I'm confused here, what do you mean that it's impossible? you just added by sorry to your code, I don't know what that's supposed to mean.

Thanks for your advice! I use 'by sorry' just as a placeholder here :).

Kenny Lau (Jun 30 2025 at 09:53):

yes, but what do you mean by "impossible"?

Kenny Lau (Jun 30 2025 at 09:54):

oh, now I understand

Kenny Lau (Jun 30 2025 at 09:54):

yeah there's certainly nothing in your axioms saying that the induction has to produce what you think it would produce!

Kenny Lau (Jun 30 2025 at 09:55):

I can certainly build a function that swaps the output for 0 and 1 and it will still satisfy your axioms!

Jz Pan (Jun 30 2025 at 09:56):

Kenny Lau said:

I can certainly build a function that swaps the output for 0 and 1 and it will still satisfy your axioms!

Or constant function

Yusuke Inoue (Jun 30 2025 at 10:00):

I think any instance that satisfies the axioms has to use something derived from the type's recursor or something like that to satisfy 'induction'.

Yusuke Inoue (Jun 30 2025 at 10:01):

and that makes computing possible

Yusuke Inoue (Jun 30 2025 at 12:22):

I guess maybe in meta language can prove 'for all N : Type , PeanoAxioms N -> conv0', but conv0 cannot be proved in Lean itself

Aaron Liu (Jun 30 2025 at 12:29):

It's actually inconsistent with the axiom of choice:

import Mathlib

class PeanoAxioms (N : Type) extends Zero N where
  succ : N -> N
  zeroNoSucc : n : N, ¬ succ n = 0
  succCancel : a b : N, succ a = succ b  a = b
  induction : f : N  Sort*, f 0  (n : N, f n  f (succ n))  n : N, f n

postfix:100 "++" => PeanoAxioms.succ

namespace PeanoAxioms

variable {N : Type}[PeanoAxioms N]

theorem conv0 {f : N  Sort*} (base : f 0) (succ : n : N, f n  f (n++)) : induction f base succ 0 = base := by sorry

example : False := by
  have := @conv0 Nat {
    zero := Nat.zero
    succ := Nat.succ
    zeroNoSucc := Nat.succ_ne_zero
    succCancel := @Nat.succ.inj
    induction f z s n := by classical exact if hf : f = fun _ => Bool then hf  false else @Nat.rec f z s n
  } (fun _ => Bool) true fun _ _ => true
  simp at this

Kenny Lau (Jun 30 2025 at 12:29):

Yusuke Inoue said:

I guess maybe in meta language can prove 'for all N : Type , PeanoAxioms N -> conv0', but conv0 cannot be proved in Lean itself

yes, that's a meta theorem, so not a theorem

Kenny Lau (Jun 30 2025 at 12:31):

for your purposes I think you should instead make conv0 and conv_succ part of the axioms

Aaron Liu (Jun 30 2025 at 12:33):

I think you can still computably derive an induction' that has the same signature but also additionally satisfies conv0 and conv_succ

Kenny Lau (Jun 30 2025 at 12:37):

In that case please swap the names, induction' for the provided one and induction for the derived one

Yusuke Inoue (Jun 30 2025 at 12:38):

Aaron Liu said:

I think you can still computably derive an induction' that has the same signature but also additionally satisfies conv0 and conv_succ

Could you please make it clearer? I'm afraid I can't fully understand.

Aaron Liu (Jun 30 2025 at 12:59):

import Mathlib

class PeanoAxioms (N : Type) extends Zero N where
  succ : N -> N
  zeroNoSucc : n : N, ¬ succ n = 0
  succCancel : a b : N, succ a = succ b  a = b
  induction' : f : N  Sort*, f 0  (n : N, f n  f (succ n))  n : N, f n

namespace PeanoAxioms
variable {N : Type} [PeanoAxioms N]

scoped postfix:100 "++" => PeanoAxioms.succ

variable (N) in
def ofNat (n : Nat) : N :=
  match n with
  | 0 => 0
  | n + 1 => (ofNat n)++

instance decEq (n m : N) : Decidable (n = m) :=
  induction' (fun k =>  j, Decidable (j = k))
    (induction' (fun j => Decidable (j = _)) (.isTrue rfl) (fun j _ => .isFalse (zeroNoSucc j)))
    (fun k _ => induction' (fun j => Decidable (j = _)) (.isFalse (Ne.symm (zeroNoSucc k)))
      (fun j _ => decidable_of_iff (j = k) congrArg (·++), succCancel j k)) m n

variable (N) in
theorem ofNat_injective : (ofNat N).Injective := sorry

variable (N) in
theorem ofNat_surjective : (ofNat N).Surjective := sorry

def toNat (n : N) := Nat.find (p := fun c => ofNat N c = n) (ofNat_surjective N n)

def induction (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)) (n : N) : f n := sorry

def cov0 (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)): induction f zero succ 0 = zero := sorry

def cov_succ (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)) (n : N) : induction f zero succ (n++) = succ n (induction f zero succ n) := sorry

end PeanoAxioms

Kenny Lau (Jun 30 2025 at 13:01):

induction' should have @[elab_as_elim] (and implicit motive) so you don't need to specify the motive explicitly

Kenny Lau (Jun 30 2025 at 13:01):

@Yusuke Inoue in words, see how induction above is derived from the axiom induction' and satisfies the conv lemmas you wanted

Jz Pan (Jun 30 2025 at 14:27):

Aaron Liu said:

It's actually inconsistent with the axiom of choice:

import Mathlib

class PeanoAxioms (N : Type) extends Zero N where
  succ : N -> N
  zeroNoSucc : n : N, ¬ succ n = 0
  succCancel : a b : N, succ a = succ b  a = b
  induction : f : N  Sort*, f 0  (n : N, f n  f (succ n))  n : N, f n

postfix:100 "++" => PeanoAxioms.succ

namespace PeanoAxioms

variable {N : Type}[PeanoAxioms N]

theorem conv0 {f : N  Sort*} (base : f 0) (succ : n : N, f n  f (n++)) : induction f base succ 0 = base := by sorry

example : False := by
  have := @conv0 Nat {
    zero := Nat.zero
    succ := Nat.succ
    zeroNoSucc := Nat.succ_ne_zero
    succCancel := @Nat.succ.inj
    induction f z s n := by classical exact if hf : f = fun _ => Bool then hf  false else @Nat.rec f z s n
  } (fun _ => Bool) true fun _ _ => true
  simp at this

Because conv0 is not necessarily true for general; it should be a field of PeanoAxioms, as well as conv_succ

Kenny Lau (Jun 30 2025 at 14:34):

@Jz Pan see alternative route above

Jz Pan (Jun 30 2025 at 14:39):

Oh amazing. I haven't realized that DecidableEq can be obtained.

Aaron Liu (Jun 30 2025 at 14:41):

You do get induction, after all. It's just that you don't get any computational properties, but that is irrelevant here since Decidable is a subsingleton.

Aaron Liu (Jun 30 2025 at 14:43):

although maybe making it an instance isn't the best idea if we also want a PeanoAxioms Nat

Kenny Lau (Jun 30 2025 at 14:46):

you might as well state N \~- \N as the only axiom

Kenny Lau (Jun 30 2025 at 14:46):

or better, use actual model theory :upside_down:

Kenny Lau (Jun 30 2025 at 14:46):

(these aren't constructive feedbacks, please ignore)

Jz Pan (Jun 30 2025 at 15:06):

What I've tried is at here #general > Lean companion to "Analysis I" - discussion @ 💬 and I've got everything if assuming DecidableEq

Yusuke Inoue (Jun 30 2025 at 15:32):

Aaron Liu said:

import Mathlib

class PeanoAxioms (N : Type) extends Zero N where
  succ : N -> N
  zeroNoSucc : n : N, ¬ succ n = 0
  succCancel : a b : N, succ a = succ b  a = b
  induction' : f : N  Sort*, f 0  (n : N, f n  f (succ n))  n : N, f n

namespace PeanoAxioms
variable {N : Type} [PeanoAxioms N]

scoped postfix:100 "++" => PeanoAxioms.succ

variable (N) in
def ofNat (n : Nat) : N :=
  match n with
  | 0 => 0
  | n + 1 => (ofNat n)++

instance decEq (n m : N) : Decidable (n = m) :=
  induction' (fun k =>  j, Decidable (j = k))
    (induction' (fun j => Decidable (j = _)) (.isTrue rfl) (fun j _ => .isFalse (zeroNoSucc j)))
    (fun k _ => induction' (fun j => Decidable (j = _)) (.isFalse (Ne.symm (zeroNoSucc k)))
      (fun j _ => decidable_of_iff (j = k) congrArg (·++), succCancel j k)) m n

variable (N) in
theorem ofNat_injective : (ofNat N).Injective := sorry

variable (N) in
theorem ofNat_surjective : (ofNat N).Surjective := sorry

def toNat (n : N) := Nat.find (p := fun c => ofNat N c = n) (ofNat_surjective N n)

def induction (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)) (n : N) : f n := sorry

def cov0 (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)): induction f zero succ 0 = zero := sorry

def cov_succ (f : N  Sort*) (zero : f 0) (succ :  n, f n  f (succ n)) (n : N) : induction f zero succ (n++) = succ n (induction f zero succ n) := sorry

end PeanoAxioms

Wait. If we could prove cov0 here, then we could get False from it as above. However, there are no 'unsafe' operations (like introducing axioms). So maybe it's impossible.
Sorry, I've got something wrong.

Yusuke Inoue (Jul 01 2025 at 02:21):

I think it's interesting. Types that satisfy the Peano axioms are isomorphic, but they do not have to have the expected computing behaviours. The isomorphism could be used to select a 'standard' way of computing.
Could it be understood as follows: in type theory, proofs can be taken into consideration, but the Peano axioms said nothing about proofs and do not require a standard way of computing proofs.

Kenny Lau (Jul 01 2025 at 09:33):

Yusuke Inoue said:

Peano axioms said nothing about proofs

The induction in the Peano axioms is about Props, not eliminating to data


Last updated: Dec 20 2025 at 21:32 UTC