Zulip Chat Archive

Stream: lean4

Topic: Tactic simp term order


Yicheng Qian (Aug 21 2022 at 08:54):

What order does simp use to compare terms? For example,

set_option pp.all true

theorem sdf : Nat.add (Nat.add a b) c = Nat.add (Nat.add b c) a := by
  simp

/- => @Eq.{1} Nat
  (@HAdd.hAdd.{0, 0, 0} Nat Nat Nat (@instHAdd.{0} Nat instAddNat)
    (@HAdd.hAdd.{0, 0, 0} Nat Nat Nat (@instHAdd.{0} Nat instAddNat) a b) c)
  (@HAdd.hAdd.{0, 0, 0} Nat Nat Nat (@instHAdd.{0} Nat instAddNat)
    (@HAdd.hAdd.{0, 0, 0} Nat Nat Nat (@instHAdd.{0} Nat instAddNat) b c) a)
-/

why will it consider @HAdd.hAdd.{0, 0, 0} Nat Nat Nat (@instHAdd.{0} Nat instAddNat, which is a non-whnf, to be simpler than Nat.add?

Notification Bot (Aug 21 2022 at 08:59):

Yicheng Qian has marked this topic as resolved.

Notification Bot (Aug 21 2022 at 08:59):

Yicheng Qian has marked this topic as unresolved.

Yicheng Qian (Aug 21 2022 at 09:07):

This makes me worried because I think that in some cases this will make the tactic rw fail to work. Consider this example

structure Semigroup where
  carrier : Type u
  mul : carrier  carrier  carrier
  mul_assoc (a b c : carrier) : mul (mul a b) c = mul a (mul b c)

instance (S : Semigroup) : Mul S.carrier where
  mul a b := S.mul a b

instance : CoeSort Semigroup (Type u) where
  coe S := S.carrier

structure Morphism (S1 S2 : Semigroup) where
  mor : S1  S2
  resp_mul :  a b : S1, mor (a * b) = (mor a) * (mor b)

instance : CoeFun (Morphism S1 S2) (fun _ => S1 -> S2) where
  coe f := f.mor

To prove the following theorem, the simplest way seems to involve unfolding of HMul.hMul and Mul.mul (I consier this necessary because otherwise rw [S2.mul_assoc] won't work)

example {S1 S2 : Semigroup} (f : Morphism S1 S2) (a : S1) :
  f ((a * a) * (a * a)) = f a * ((f a * f a) * f a) := by
    simp [f.resp_mul]; simp [HMul.hMul, Mul.mul]; simp [S2.mul_assoc]

Yicheng Qian (Aug 21 2022 at 09:09):

If we refuse to unfold HMul.hMul and Mul.mul, then the simplest way I can come up with is to enter the conversion tactic mode

example {S1 S2 : Semigroup} (f : Morphism S1 S2) (a : S1) :
  f ((a * a) * (a * a)) = f a * ((f a * f a) * f a) :=
  calc
    f ((a * a) * (a * a)) = f (a * a) * f (a * a)     := by rw [f.resp_mul]
               _          = (f a * f a) * (f a * f a) := by rw [f.resp_mul]
               _          = S2.2 (S2.2 (f a) (f a)) (S2.2 (f a) (f a)) :=
                               by conv =>
                                  lhs; whnf
                                  args whnf whnf
               _          = S2.2 (f a) (S2.2 (S2.2 (f a) (f a)) (f a)) := by simp [S2.mul_assoc]

Mario Carneiro (Aug 21 2022 at 18:42):

The direction of simp rewrites is a library design question. We generally prefer a + b over Nat.add a b because the former will have more theorems about it: for example we would have an associativity theorem add_assoc which applies to any additive semigroup rather than just Nat.


Last updated: Dec 20 2023 at 11:08 UTC