Zulip Chat Archive

Stream: lean4

Topic: invalid projection on irreducible structures


Jun Yoshida (Sep 23 2023 at 08:55):

The following produces an error message (I am sorry its a bit long; I couldn't minimize it more):

class LeftDistribHMul (α β γ : Type _) [Add β] [Add γ] [HMul α β γ] where
  left_distrib :  (a : α) (b₁ b₂ : β), a * (b₁ + b₂) = a * b₁ + a * b₂

instance : LeftDistribHMul Nat Nat Nat where
  left_distrib l m n := Nat.mul_add l m n

def Whole (α : Type _) : Type _ := {a : α // a = a}

namespace Whole

variable {α β γ: Type _}

instance [HMul α β γ] : HMul (Whole α) (Whole β) (Whole γ) where
  hMul a b := Subtype.mk (a.1 * b.1) rfl

instance [Add α] : Add (Whole α) where
  add a₁ a₂ := Subtype.mk (a₁.1 + a₂.1) rfl

theorem left_distrib
  [Add β] [Add γ] [HMul α β γ] [LeftDistribHMul α β γ]
  (a : Whole α) (b₁ b₂ : Whole β) : a * (b₁ + b₂) = a * b₁ + a * b₂ :=
  Subtype.eq <| LeftDistribHMul.left_distrib a.1 b₁.1 b₂.1

end Whole

attribute [irreducible] Whole

class LeftDistribMul (α : Type _) [Add α] [Mul α] where
  left_distrib :  (a b c : α), a * (b + c) = a * b + a * c

variable {α : Type _}

instance [Mul α] : Mul (Whole α) := HMul.hMul

instance : LeftDistribMul (Whole Nat) where
  left_distrib x y z :=
    Whole.left_distrib x y z -- invalid projection (x * y).1

The error goes away if either

  • remove attribute [irreducible] Whole line, or
  • replace the proof by by rw [Whole.left_distrib]

Jun Yoshida (Sep 23 2023 at 08:56):

Why does isDefEq not go beyond the irreducibility?

Eric Wieser (Sep 23 2023 at 09:35):

Jun Yoshida said:

Why does isDefEq not go beyond the irreducibility?

This is the whole point of irreducibility!

Jun Yoshida (Sep 23 2023 at 09:55):

Hmm, right. Does it mean the error in this example is expected?

Sebastian Ullrich (Sep 23 2023 at 10:04):

I didn't look at the example in detail but changing reducibility between instance declaration and use is highly problematic; don't do it. Same goes for [simp] etc.

Jun Yoshida (Sep 23 2023 at 10:14):

You mean attribute [irreducible] X should not be anywhere other than just after the declaration of X?

Kevin Buzzard (Sep 23 2023 at 10:55):

That is indeed what they mean. In mathlib3 we used to do this all the time: define a thing, make the API, and then make the thing irreducible afterwards. Then the CS purists caught us doing it and told us it was terrible and evil, because there are now proofs that used to be rfl but rfl doesn't work any more. My reaction to this was always "so what? It all still works fine" but in Lean 4 they have really attempted to ban this kind of thing (for example I don't think you even can make a declaration irreducible if it's defined in another file). I have no idea why they get so upset about this, it didn't seem to cause any problems in practice in mathlib3 and actually helped to solve problems.

Sebastian Ullrich (Sep 23 2023 at 11:19):

What I described above is purely related to data structures making these subsystems much faster in Lean 4. Sometimes you can't have fast and flexible at the same time.

Jun Yoshida (Sep 23 2023 at 12:45):

I didn't know that this "making decls irreducible afterward" pattern got deprecated. The news makes me sad since I was used to it since Lean 2 & 3, too. Anyway, I understand the current Lean 4 behavior about reducibility; the kernel assumes it would be unchanged after declaration. Thank you for letting me know. So, what is the recommended design pattern hiding implementation details? For example, how about this?

@[unbox]
structure Whole (α : Type _) where
  private mk :: private val : {a : α // a = a}

Sebastian Ullrich (Sep 23 2023 at 12:48):

Yes, newtype-style structures are much preferred over [irreducible]. Note though that private is not as restricting as one might expect, e.g. you can still construct the type using anonymous constructors.

Jun Yoshida (Sep 23 2023 at 12:57):

Fortunately, I successfully got errors:

/- Another file -/

example : Whole Nat := 10,rfl
example : Whole Nat  Nat := fun n,h => n
/-
Both lines produce the following error:
invalid ⟨...⟩ notation, constructor for `Whole` is marked as private
-/

Sebastian Ullrich (Sep 23 2023 at 13:13):

Hah, thanks for checking! It is not bullet-proof, but neither is it in other languages with reflection


Last updated: Dec 20 2023 at 11:08 UTC