Yes, exactly.
Such as (==)
, in the current iteration of the min
/max
laws? With you so far, I think, although I’m not aware of other classes making this sort of allowance. When the Semigroup
law says that (<>)
should be associative, that’s not up to some particular observation function, is it? I default to interpreting such laws as holding up to any pure, safe predicate—when the documentation says x <> (y <> z) = (x <> y) <> z
, I read that as meaning that for any safe function f :: a -> Bool
, f (x <> (y <> z)) == f ((x <> y) <> z)
(where now ==
can be simple boolean equality). That’s the same standard I’d like to use with min
and max
.
Is there a practical difference between arguing for weaker laws (such as laws up to some observation function) and arguing for fewer laws? They seem like the same thing to me—a stronger law subsumes a weaker law by adding an additional restriction, which could be seen as a second law in its own right.
What strikes me as more important than the difference between weaker and fewer is the spectrum with strong laws and fewer instances on one end and few/no/weak laws and many instances on the other end.
Bodigrim says that:
That’s the argument for pushing toward the many-instances side of the spectrum—that it’d be useful. That’s what I see as the general argument against laws—more instances are always useful!
He then gives some specific examples of cases that he thinks are particularly useful for min
and max
. I draw a parallel case to one of those examples with Semigroup
, and point out that this would be useful in the same scenario that his example would be useful—by Bodigrim’s reasoning, I would expect him to object to a strict interpretation of Semigroup
's laws in that scenario as well.
But I doubt that he does. Because ‘useful’ is not the deciding factor in determining what laws a class should have. Rather, what is most important is the intended meaning of the class abstraction. <>
could represent some arbitrary binary operation—but we intend that the meaning of the Semigroup
class is to represent, well, a semigroup. And to do that, <>
must be associative.
Likewise, if min
and max
are to represent the abstract concepts of ‘take the lesser/greater of these two arguments’, it would be incorrect for them to (observably—under the hood I don’t care what they do) construct a third value. It might be ‘useful’, but it’s incorrect, and that’s that! If we let usefulness override our sense of what class operations are meant to represent, we would not have laws, because laws only get in the way of having more instances and being more useful.