Zulip Chat Archive

Stream: lean4

Topic: OfNat Even (n * 2)


Michiel Peeters (Sep 13 2024 at 04:41):

I'm following the FP in Lean 4 book and one of the exercises is to create an even numbers type and define some type class instances for it. One of them is OfNat to overload the (even) numeric literals. The first example the book gave was for strict positive integers called Pos and the type class instance was defined as OfNat Pos (n + 1). In this case, lean is smart enough to deconstruct (n + 1), disallowing 0 and this only provide an OfNat instance for strict positive integers.

I thought to do something similar for Even: OfNat Even (n * 2), I thought that lean was maybe able to do something similar, disallowing odd numbers like this because they can't be written as 2 * n for some n. However this does not work and I can't seem to find why exactly. My gut says it has something to do with Nat being defined as successors, so + is easier to deconstruct somehow, but I can't find any substantial evidence for that claim.

I would love if someone could tell or show me what kind of expressions are allowed in OfNat declarations and how they are deconstructed. Thanks!

Floris van Doorn (Sep 13 2024 at 05:20):

I believe that the Lean elaborator has special support to solve n =?= ?k +1, but not for n =?= ?k * 2.
I don't know if it's possible to add this yourself without changing Lean (unification hints do something similar, but I don't know if they can do this).

The following works a little bit, but it's not ideal (you have to write OfNat.ofNat, the resulting term actually has nested ofNat's, and it doesn't work for 6, only for _ * 2).

import Mathlib.Algebra.Ring.Parity

instance (n : ) : OfNat { k :  // Even k } (n * 2) :=
  n * 2, even_two.mul_left n

#check (OfNat.ofNat (3 * 2) : { k :  // Even k })

This is also possible, but probably a very bad idea :-)

instance (n : ) : OfNat { k :  // Even k } n :=
  n * 2, even_two.mul_left n

#eval (7 : { k :  // Even k }) -- 14

Daniel Weber (Sep 13 2024 at 13:05):

You can also do

instance (n : ) : OfNat { k :  // Even k } n :=
  if hn : Even n then n, hn else 0, even_zero

or even

instance : Inhabited { k :  // Even k } := ⟨⟨0, even_zero⟩⟩

instance (n : ) : OfNat { k :  // Even k } n :=
   if hn : Even n then n, hn else panic "Error: number not even"

Last updated: May 02 2025 at 03:31 UTC