Re: Show, Eq not necessary for Num [Was: Revamping the numeric classes]

Brian Boutel
The fact that equality can be trivially defined as bottom does not imply that it should be a superclass of Num, it only explains that there is an ugly way of working around the problem.
There is nothing trivial or ugly about a definition that reflects reality and bottoms only where equality is undefined.
I think there is. If I design a class and derive it from Num with (==) is bottom, I am allowed to apply to it functions requiring a Num argument, but I have no guarantee it will work. The implementor of that function can change its internals (to use (==)), and suddenly my previously working program is non-terminating. If I defined (==) to give a run time error, it'd be a bit better, but I'd much prefer the compiler to tell me about this in advance.
Of course, if you do not need to apply equality to your "numeric" type then having to define it is a waste of time, but consider this:
It's not about "needing to apply", but about finding a reasonable definition.
- Having a class hierarchy at all (or making any design decision) implies compromise.
I think the argument is that we should move Eq and Show *out* of the Num hierarchy. Less hierarchy - less compromise.
- The current hierarchy (and its predecessors) represent a reasonable compromise that meets most needs.
Obviously a lot of people seem to think we could find compromises that are more reasonable.
- Users have a choice: either work within the class hierarchy and accept the pain of having to define things you don't need in order to get the things that come for free,
Isn't it a good idea to reduce the amount of pain?
or omit the instance declarations and work outside the hierarchy. In that case you will not be able to use the overloaded operator symbols of the class, but that is just a matter of concrete syntax, and ultimately unimportant.
I don't think syntax is unimportant. -kzm -- If I haven't seen further, it is by standing in the footprints of giants

Ketil Malde wrote:
Brian Boutel
writes: - Having a class hierarchy at all (or making any design decision) implies compromise.
I think the argument is that we should move Eq and Show *out* of the Num hierarchy. Less hierarchy - less compromise.
Can you demonstrate a revised hierarchy without Eq? What would happen to Ord, and the numeric classes that require Eq because they need signum?
- The current hierarchy (and its predecessors) represent a reasonable compromise that meets most needs.
Obviously a lot of people seem to think we could find compromises that are more reasonable.
I would put this differently. "A particular group of people want to change the language to make it more convenient for their special interests."
- Users have a choice: either work within the class hierarchy and accept the pain of having to define things you don't need in order to get the things that come for free,
Isn't it a good idea to reduce the amount of pain?
Not always.
or omit the instance declarations and work outside the hierarchy. In that case you will not be able to use the overloaded operator symbols of the class, but that is just a matter of concrete syntax, and ultimately unimportant.
I don't think syntax is unimportant.
I wrote that *concrete* syntax is ultimately unimportant, not *syntax*. There is a big difference. In particular, *lexical syntax*, the choice of marks on paper used to represent a language element, is not important, although it does give rise to arguments, as do all mattters of taste and style. Thre are not enough usable operator symbols to go round, so they get overloaded. Mathematicians have overloaded common symbols like (+) and (*) for concepts that have may some affinity with addition and multiplication in arithmetic, but which are actually quite different. That's fine, because, in context, expert human readers can distinguish what is meant. From a software engineering point of view, though, such free overloading is dangerous, because readers may assume, incorrectly, that an operator has properties that are typically associated with operators using that symbol. This may not matter in a private world where the program writer is the only person who will see and use the code, and no mission-critial decisions depend on the results, but it should not be the fate of Haskell to be confined to such use. Haskell could have allowed free ad hoc overloading, but one of the first major decisions made by the Haskell Committee in 1988 was not to do so. Instead, it adopted John Hughes' proposal to introduce type classes to control overloading. A symbol could only be overloaded if the whole of a group of related symbols (the Class) was overloaded with it, and the class hierarchy provided an even stronger constraint by restricting overloading of the class operators to cases where other classes, intended to be closely related, were also overloaded. This tended to ensure that the new type at which the classes were overloaded had strong resemblences to the standard types. Simplifying the hierarchy weakens these constraints and so should be approached with extreme caution. Of course, the details of the classes and the hierarchy have changed over the years - there is, always has been and always will be pressure to make changes to meet particular needs - but the essence is still there, and the essence is of a general-purpose language, not a domain-specific language for some branches of mathematics. A consequence of this is that certain uses of overloaded symbols are inconvenient, because they are too far from the mainstream intended meaning. If you have such a use, and you want to write in Haskell, you have to choose other lexical symbols to represent your operators. You make your choice. --brian

Sat, 10 Feb 2001 14:09:59 +1300, Brian Boutel
Can you demonstrate a revised hierarchy without Eq? What would happen to Ord, and the numeric classes that require Eq because they need signum?
signum doesn't require Eq. You can use signum without having Eq, and you can sometimes define signum without having Eq (e.g. on functions). Sometimes you do require (==) to define signum, but it has nothing to do with superclasses. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK

On Sat, Feb 10, 2001 at 07:17:57AM +0000, Marcin 'Qrczak' Kowalczyk wrote:
Sat, 10 Feb 2001 14:09:59 +1300, Brian Boutel
pisze: Can you demonstrate a revised hierarchy without Eq? What would happen to Ord, and the numeric classes that require Eq because they need signum?
signum doesn't require Eq. You can use signum without having Eq, and you can sometimes define signum without having Eq (e.g. on functions). Sometimes you do require (==) to define signum, but it has nothing to do with superclasses.
Can you elaborate? What do you mean by signum for functions? The pointwise signum? Then abs would be the pointwise abs as well, right? That might work, but I'm nervous because I don't know the semantics for signum/abs in such generality. What identities should they satisfy? (The current Haskell report says nothing about the meaning of these operations, in the same way it says nothing about the meaning of (+), (-), and (*). Compare this to the situation for the Monad class, where the fundamental identities are given. Oddly, there are identities listed for 'quot', 'rem', 'div', and 'mod'. For +, -, and * I can guess what identities they should satisfy, but not for signum and abs.) (Note that pointwise abs of functions yields a positive function, which are not ordered but do have a sensible notion of max and min.) Best, Dylan Thurston

Sat, 10 Feb 2001 11:25:46 -0500, Dylan Thurston
Can you elaborate? What do you mean by signum for functions? The pointwise signum?
Yes.
Then abs would be the pointwise abs as well, right?
Yes.
That might work, but I'm nervous because I don't know the semantics for signum/abs in such generality.
For example signum x * abs x == x, where (==) is not Haskell's equality but equivalence. Similarly to (x + y) + z == x + (y + z). If (+) can be implicitly lifted to functions, then why not signum? Note that I would lift neither signum nor (+). I don't feel the need. It can't be uniformly applied to e.g. (<) whose result is Bool and not some lifted Bool, so better be consistent and lift explicitly. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK

On Sat, Feb 10, 2001 at 11:25:46AM -0500, Dylan Thurston wrote:
Can you elaborate? What do you mean by signum for functions? The pointwise signum? Then abs would be the pointwise abs as well, right? That might work, but I'm nervous because I don't know the semantics for signum/abs in such generality. What identities should they satisfy? (The current Haskell report says nothing about the meaning of these operations, in the same way it says nothing about the meaning of (+), (-), and (*). Compare this to the situation for the Monad class, where the fundamental identities are given. Oddly, there are identities listed for 'quot', 'rem', 'div', and 'mod'. For +, -, and * I can guess what identities they should satisfy, but not for signum and abs.)
Pointwise signum and abs are common in analysis. The identity is: signum f * abs f = f I've already done the pointwise case. As I've pointed out before, abs has the wrong type for doing anything with vector spaces, though, perhaps, abs is a distinct notion from norm. On Sat, Feb 10, 2001 at 11:25:46AM -0500, Dylan Thurston wrote:
(Note that pointwise abs of functions yields a positive function, which are not ordered but do have a sensible notion of max and min.)
The ordering you're looking for needs a norm. If you really want a notion of size on functions, you'll have to do it with something like one of the L^p norms for continua and the \ell^p norms for discrete spaces which are instances of Enum. There is a slightly problematic aspect with this in that the domain of the function does not entirely determine the norm, and furthermore adequately dealing with the different notions of measure on these spaces with the type system is probably also intractable. The sorts of issues raised by trying to define norms on functions probably rather quickly relegate it to something the user should explicitly define, as opposed to something that should appear in a Prelude standard or otherwise. That said, one could do something like instance Enum a => Enum (MyTree a) where ... -- it's tricky, but possible, you figure it out instance (Enum a, RealFloat b) => NormedSpace (MyTree a -> b) where norm f = approxsum $ zipWith (*) (map f . enumFrom $ toEnum 0) weights where weights = map (\x -> 1/factorial x) [0..] approxsum [] = 0 approxsum (x:xs)| x < 1.0e-6 = 0 | otherwise = x + approxsum xs and then do the usual junk where instance NormedSpace a => Ord a where f < g = norm f < norm g ... Cheers, Bill

Marcin 'Qrczak' Kowalczyk wrote:
Sat, 10 Feb 2001 14:09:59 +1300, Brian Boutel
pisze: Can you demonstrate a revised hierarchy without Eq? What would happen to Ord, and the numeric classes that require Eq because they need signum?
signum doesn't require Eq. You can use signum without having Eq, and you can sometimes define signum without having Eq (e.g. on functions). Sometimes you do require (==) to define signum, but it has nothing to do with superclasses.
Let me restate my question more carefully: Can you demonstrate a revised hierarchy without Eq? What would happen to Ord and the numeric classes with default class method definitions that use (==) either explicitly or in pattern matching against numeric literals? Both Integral and RealFrac do this to compare or test the value of signum. In an instance declaration, if a method requires operations of another class which is not a superclass of the class being instanced, it is sufficient to place the requirement in the context, but for default class method definitions, all class methods used must belong to the class being defined or its superclasses. --brian

On Sun, Feb 11, 2001 at 01:37:28PM +1300, Brian Boutel wrote:
Let me restate my question more carefully:
Can you demonstrate a revised hierarchy without Eq? What would happen to Ord and the numeric classes with default class method definitions that use (==) either explicitly or in pattern matching against numeric literals? Both Integral and RealFrac do this to compare or test the value of signum.
I've been working on writing up my preferred hierarchy, but the short answer is that classes that are currently derived from Ord often do require Eq as superclasses. In the specific cases: I think possibly divMod and quotRem should be split into separate classes. It seems to me that divMod is the more fundamental pair: it satisfies the identity mod (a+b) b === mod a b div (a+b) b === 1 + div a b in addition to (div a b)*b + mod a b === a. This identity is not enough to specify divMod competely; another reasonable choice for Integers would be to round to the nearest integer. But this is enough to make it useful for many applications. quotRem is also useful (although it only satisfies the second of these), and does require the ordering (and ==) to define sensibly, so I would make it a method of a subclass of Ord (and hence Eq). So I would tend to put these into two separate classes: class (Ord a, Num a) => Real a class (Num a) => Integral a where div, mod :: a -> a -> a divMod :: a -> a -> (a,a) class (Integral a, Real a) => RealIntegral a where quot, rem :: a -> a -> a quotRem :: a -> a -> (a,a) I haven't thought about the operations in RealFrac and their semantics enough to say much sensible, but probably they will again require Ord as a superclass. In general, I think a good approach is to think carefully about the semantics of a class and its operations, and to declare exactly the superclasses that are necessary to define the semantics. Note that sometimes there are no additional operations. For instance, declaring a class to be an instance of Real a should mean that the ordering (from Ord) and the numeric structure (from Num) are compatible. Note also that we cannot require Eq to state laws (the '===' above); consider the laws required for the Monad class to convince yourself. Best, Dylan Thurston

Sun, 11 Feb 2001 13:37:28 +1300, Brian Boutel
Can you demonstrate a revised hierarchy without Eq? What would happen to Ord and the numeric classes with default class method definitions that use (==) either explicitly or in pattern matching against numeric literals?
OK, then you can't write these default method definitions. I'm against removing Eq from the numeric hierarchy, against making Num instances for functions, but I would probably remove Show. I haven't seen a sensible proposal of a replacement of the whole hierarchy.
In an instance declaration, if a method requires operations of another class which is not a superclass of the class being instanced, it is sufficient to place the requirement in the context,
Better: it is sufficient if the right instance is defined somewhere. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK

Sun, 11 Feb 2001 13:37:28 +1300, Brian Boutel
Can you demonstrate a revised hierarchy without Eq? What would happen to Ord and the numeric classes with default class method definitions that use (==) either explicitly or in pattern matching against numeric literals?
I anticipate that some restructuring of the numeric classes must be done in order to accomplish this. I am, of course, attempting to contrive such a beast for my own personal use. On Sun, Feb 11, 2001 at 07:59:38AM +0000, Marcin 'Qrczak' Kowalczyk wrote:
OK, then you can't write these default method definitions. I'm against removing Eq from the numeric hierarchy, against making Num instances for functions, but I would probably remove Show. I haven't seen a sensible proposal of a replacement of the whole hierarchy.
Well, there are a couple of problems with someone like myself trying
to make such a proposal. First, I'm a bit too marginalized and/or
committed to a radical alternative. Second, I don't have the right
associations or perhaps other resources.
Removing Eq sounds like a good idea to me, in all honesty, though I
think numeric instances for functions (at least by default) aren't
great ideas. More details follow:
Regarding Eq, there are other types besides functions which might
not be good ideas to define equality on, either because they're not
efficiently implementable or are still inappropriate. Matrix types
aren't good candidates for defining equality, for one. Another one
you might not want to define equality on are formal power series
represented by infinite lists, since equality tests will never
terminate. A third counterexample comes, of course, from graphics,
where one might want to conveniently scale and translate solids.
Testing meshes and surface representations for equality is once
again not a great idea. Perhaps these counterexamples are a little
contrived, but perhaps other people can come up with better ones.
As far as the function instances of numeric types, there are some
nasty properties that they have that probably make it a bad idea.
In particular, I discovered that numeric literals' fromInteger
property creates the possibility that something which is supposed
to be a scalar or some other numeric result might accidentally be
applied. For instance, given an expression with an intermediate
numeric result like:
f u v . g x y $ h z
which is expected to produce a number, one could accidentally apply
a numeric literal or something bound to one to some arguments, creating
a bug. So this is for at least partial agreement, though I think it
should be available in controlled circumstances. Local module
importations and/or scoped instances might help here, or perhaps
separating out code that relies upon them into a module where the
instance is in scope, as it probably needs control which is that tight.
Sun, 11 Feb 2001 13:37:28 +1300, Brian Boutel
In an instance declaration, if a method requires operations of another class which is not a superclass of the class being instanced, it is sufficient to place the requirement in the context,
On Sun, Feb 11, 2001 at 07:59:38AM +0000, Marcin 'Qrczak' Kowalczyk wrote:
Better: it is sufficient if the right instance is defined somewhere.
Again, I'd be careful with this idea. It's poor design to unnecessarily restrict the generality of code. Of course, it's poor design to not try to enforce necessary conditions in the type system, too, which is why library design is nontrivial. And, of course, keeping it simple enough for use by the general populace (or whatever semblance thereof exists within the Haskell community) might well conflict with the desires of persons like myself who could easily fall prey to the accusation that they're trying to turn Haskell into a computer algebra system, and adds yet another constraint to the library design making it even tougher. Cheers, Bill

Marcin 'Qrczak' Kowalczyk wrote:
I'm against removing Eq from the numeric hierarchy, against making Num instances for functions, but I would probably remove Show. I haven't seen a sensible proposal of a replacement of the whole hierarchy.
Then we probably are in agreement. --brian
participants (5)
-
Brian Boutel
-
Dylan Thurston
-
Ketil Malde
-
qrczak@knm.org.pl
-
William Lee Irwin III