Zulip Chat Archive

Stream: general

Topic: typeclass


Kenny Lau (Mar 15 2018 at 18:27):

why does this have no problem:

class add_comm_monoid (α : Type u) extends add_monoid α, add_comm_semigroup α

class add_group (α : Type u) extends add_monoid α, has_neg α :=
(add_left_neg : ∀ a : α, -a + a = 0)

class add_comm_group (α : Type u) extends add_group α, add_comm_monoid α

but this gives me an error?

class has_upair extends has_zmem α :=
(upair : α → α → α)
(zmem_upair_iff_eq_or_eq : ∀ x y z, z ∈ upair x y ↔ z = x ∨ z = y)

class has_sUnion extends has_zmem α :=
(sUnion : α → α)
(zmem_sUnion_iff_zmem_zmem : ∀ x z, z ∈ sUnion x ↔ ∃ t, z ∈ t ∧ t ∈ x)

class has_sUnion_upair extends has_sUnion α, has_upair α

Kenny Lau (Mar 15 2018 at 18:27):

error:

invalid 'structure' header, field 'to_has_zmem' from 'zfc.has_upair' has already been declared

Simon Hudon (Mar 15 2018 at 18:28):

Why isn't α a parameter of has_upair and has_sUnion?

Kenny Lau (Mar 15 2018 at 18:28):

oh it's a variable I declared before

Kenny Lau (Mar 15 2018 at 18:28):

(sorry for not providing MWE)

Simon Hudon (Mar 15 2018 at 18:33):

Ah! I see! This is what is called diamond-shaped inheritance scheme. It causes you to inherit to_has_zmem multiple times which causes it to clash with itself.

Simon Hudon (Mar 15 2018 at 18:33):

(C++ programmers also know that as "diamond of death")

Simon Hudon (Mar 15 2018 at 18:34):

They have been carefully exorcised from the basic libraries

Simon Hudon (Mar 15 2018 at 18:36):

Is there a way to not make has_upair inherit has_zmem?

Simon Hudon (Mar 15 2018 at 18:37):

You could change:

class has_upair extends has_zmem α :=

into

class has_upair [has_zmem α] :=

Kenny Lau (Mar 15 2018 at 18:37):

then why does the first one work?

Simon Hudon (Mar 15 2018 at 18:39):

Good question. I wonder if that's because add_comm_monoid doesn't have fields. You can basically inline it in the extends clause of add_comm_group

Simon Hudon (Mar 15 2018 at 18:42):

If that's the case, you maybe could take advantage of it by splitting has_upair in two:

class has_upair_1 [has_zmem α] :=
(upair : α → α → α)
(zmem_upair_iff_eq_or_eq : ∀ x y z, z ∈ upair x y ↔ z = x ∨ z = y)

class has_upair_2 extends has_zmem α,  has_upair  α

I'm not sure if that would work but it might be worth a try

Kenny Lau (Mar 15 2018 at 18:43):

class has_sUnion_upair extends has_zmem α :=
(upair : α → α → α)
(zmem_upair_iff_eq_or_eq : ∀ x y z, z ∈ upair x y ↔ z = x ∨ z = y)
(sUnion : α → α)
(zmem_sUnion_iff_zmem_zmem : ∀ x z, z ∈ sUnion x ↔ ∃ t, z ∈ t ∧ t ∈ x)

instance has_sUnion_upair.to_has_sUnion [s : has_sUnion_upair α] : has_sUnion α :=
{ ..s }

instance has_sUnion_upair.to_has_upair [s : has_sUnion_upair α] : has_upair α :=
{ ..s }

Kenny Lau (Mar 15 2018 at 18:43):

this is what i did

Simon Hudon (Mar 15 2018 at 18:44):

The part I don't like about your solution is that I believe it forces you to duplicate the statement of your laws.

Kenny Lau (Mar 15 2018 at 18:46):

the part I don't like about your solution is that I would have to have has_zmem as my hypothesis each time

Simon Hudon (Mar 15 2018 at 18:47):

No. If you use has_upair_2, it comes with has_zmem

Kenny Lau (Mar 15 2018 at 18:48):

oh...

Kenny Lau (Mar 15 2018 at 18:48):

so your solution is basically like "distrib"

Kenny Lau (Mar 15 2018 at 18:48):

create a useless class that only has distributivity

Simon Hudon (Mar 15 2018 at 18:50):

You could say that

Simon Hudon (Mar 15 2018 at 18:53):

Actually, useless is not accurate: try commenting it out to see if it's useful

Kenny Lau (Mar 15 2018 at 18:54):

I mean distrib is useless in the sense that no mathematician cares about it

Simon Hudon (Mar 15 2018 at 18:56):

I think it's still useful. It might not be an interesting structure but for some theorems, you may only care about distributivity without a whole semiring

Simon Hudon (Mar 15 2018 at 18:58):

The same theorem or tactics could then be applicable whether you have a semiring or a distributive lattice

Simon Hudon (Mar 15 2018 at 19:03):

In the case of my solution, the has_upair_1 is more of a coding trick, you're right. I think it happens rarely enough that it's an ugliness we can live with. I would prefer if diamond shaped inheritance was supported properly but it has been ruled out for performance reason

Mario Carneiro (Mar 15 2018 at 21:20):

@Kenny Lau The original code works because it is using the old structure command to merge the fields together. People seem to be scared of anything marked "old" though, so if you want to recover this behavior with the new structure command, rather than creating a useless typeclass, you should extend has_upair and restate the axioms of has_sUnion, then construct a parent instance for has_sUnion (or vice versa).

Kenny Lau (Mar 15 2018 at 21:55):

so if I use old structure, everything will work?

Mario Carneiro (Mar 15 2018 at 21:56):

for some value of "everything"

Kevin Buzzard (Mar 15 2018 at 22:37):

I guess whether or not it will work in Lean 4 is another matter...

Kevin Buzzard (Mar 15 2018 at 22:42):

I guess the other thing is that presumably there was a reason the structure command was changed. Hmm, they might only be performance-related though.

Simon Hudon (Mar 15 2018 at 22:48):

I think they are. Leo considered the price to be too high despite C++ and Eiffel offering the feature with reasonable performances

Andrew Ashworth (Mar 15 2018 at 22:49):

eh, most large software projects have moved away from large inheritance trees

Simon Hudon (Mar 15 2018 at 22:51):

Have they? For performance reasons? I seem to remember it being a bottomless well of bugs in C++ because the design is kind of dumb. As far as I know, the feature is still in use in Eiffel code bases

Andrew Ashworth (Mar 15 2018 at 22:53):

not for performance, but because most people do inheritance wrong. this is the feeling i get from the places i've worked at with large code-bases

Andrew Ashworth (Mar 15 2018 at 22:54):

if you asked most people what the liskov substitution principle was they'd cross their eyes and wonder what you'd had for breakfast

Andrew Ashworth (Mar 15 2018 at 22:57):

well, that's a bit unfair, LSP is a bit jargon-ny, but the point is, it's easy to shoot yourself in the foot with misuse of inheritance

Simon Hudon (Mar 15 2018 at 23:19):

I think that's one reason Eiffel got inheritance right. Have you ever used it?


Last updated: Dec 20 2023 at 11:08 UTC