Zulip Chat Archive

Stream: lean4

Topic: Writing theorems about ofNat


Eric Wieser (Jan 20 2025 at 00:19):

Is there a way of writing this lemma such that it doesn't introduce superfluous ofNat wrappers?

def Int.factorial : Int  Int
| negSucc _ => 0
| (0 : Nat) => 1
| (n + 1 : Nat) => (n + 1) * factorial n
termination_by n => n.toNat

theorem Int.factorial_ofNat_succ (n : Nat) :
  Int.factorial (OfNat.ofNat <| n.succ) = OfNat.ofNat n.succ * Int.factorial (OfNat.ofNat n) := sorry

-- set_option pp.natLit true
-- set_option pp.explicit true
example : Int.factorial 3 = 6 := by
  rw [Int.factorial_ofNat_succ]
  -- want `3 * Int.factorial 2 = 6`, not
  guard_target =ₛ OfNat.ofNat (Nat.succ 2) * Int.factorial (OfNat.ofNat 2) = 6
  -- aka
  guard_target =ₛ OfNat.ofNat (Nat.succ (OfNat.ofNat <| nat_lit 2)) * Int.factorial (OfNat.ofNat (OfNat.ofNat <| nat_lit 2)) = 6
  sorry

example : 3 * Int.factorial 2 = 6 := by
  rw [ Int.factorial_ofNat_succ]
  -- want `Int.factorial 3 = 6`, not
  guard_target  =ₛ Int.factorial (OfNat.ofNat (Nat.succ 2)) = 6
  sorry

Eric Wieser (Jan 20 2025 at 00:24):

The context is docs#Real.Gamma_ofNat_eq_factorial, which seems to follow the antipattern of using ofNat on one side of the equation, and skipping it on the other. Despite this, the lemma actually half-works as intended!

import Mathlib

set_option pp.natLit true
example (x) (hx : Nat.factorial 36 = x) : Real.Gamma 37 = x := by
  rw [Real.Gamma_ofNat_eq_factorial] -- miraculously does the right thing
  guard_target =ₛ (Nat.factorial 36 : ) = x
  rw [ Real.Gamma_ofNat_eq_factorial] -- makes a mess
  -- goal is `Real.Gamma (OfNat.ofNat (36 + 1)) = x`

Eric Wieser (Jan 20 2025 at 00:41):

Without having a clear view of what is going on here, one possible fix might be to change ofNat to take a

structure NatLit where lit : Nat

and have Meta.isDefeq handle this specially to always assign {lit := nat_lit n} to such terms and never {lit := OfNat.ofNat _}


Last updated: May 02 2025 at 03:31 UTC