简体   繁体   中英

Should I instantiate the Num type class for a type that questionably fits the interface?

It seems to me that the Num type class consists of a pretty arbitrary collection of functions. There are lots of types that naturally have + and * operations, but are problematic as instances of Num , due to the presence of abs , signum , and fromInteger . I can't find any discussion of the design philosophy behind this class, so it's not clear to me if there is a sensible rationale here, or if it's an unfortunate historical oddity.

I'll give an illustration of my question. Suppose I'm implementing a Matrix class, with components that are Double s. I can obviously implement + , * , - , and negate . Maybe fromInteger x could give a 1x1 Matrix with component the Double value fromInteger x . It's less obvious what to do with abs and signum , but I could come up with something that satisfies the rule (from the class's documentation):

abs x * signum x == x

The objection to this idea is that my instance of Num is not fulfilling some implicit rules that people expect of Num . My * is a partial function (assuming the size of the Matrix is a runtime parameter), which is not true for the usual instances like Double and Int . And it doesn't commute. Whatever I come up with for abs and signum are not going to satisfy everyone's expectations.

The objection to this objection is that my Matrix multiplication is going to be a partial function anyway (and in this kind of type that seems to be accepted in the Haskell community), so why does it matter if it's * in particular that is the partial function? And if my abs and signum satisfy the rule from the documentation, then I've fulfilled my side of the bargain. Anyone relying on anything more from a Num instance is in the wrong.

Should a type like Matrix be an instance of Num ?

Don't make Num instances for non-rings. It's just confusing.

Of course, you can often define instances which do something useful , but if it's not completely obvious what then better just define a plain function with descriptive name, or some weaker class instance with better-defined semantics. If somebody wants to use this with short operators or polymorphic Num functions, they can still define that locally in their own module (preferrably with a simple newtype wrapper.

In particular, a Num -instance for general (dynamically-sized) matrices is problematic because it's not obvious what should happen when the dimensions don't match. What behaviour do you want to generalise?
What I would consider a good instance is matrices of fixed quadratic size (ie linear endomorphisms on a given vector space). In this case, multiplication is evidently composition , and number literals would be taken as constant-diagonal matrices, so 1 is actually multiplicative identity. Like what you write in maths contexts.

But that's not compatible with your idea of arbitrarily choosing the size of number-literals as 1×1! People would expect 2 * m to work, but it crashes. Well, better crash than give unexpected results; unfortunately it's tempting to come up with some clever way of defining multiplication in a suitable way. For instance, we could block-diagonal-copy the smaller matrix until it's large enough, perhaps only do this in the 1×1 case... well, Matlab does this kind of ad-hoc stuff, but please! let's not take such a horrible language as a model for what's good ideas.

If you have something that's obviously an additive group, indeed vector space, then make it a VectorSpace ! If you also have a multiplication, but it's partial, then better only define it as a plain function.

If you fancy, you can define instances for the fine finely staggered numeric-prelude classes. Personally (though I like the idea of this project) I couldn't yet be bothered to use it anywhere, because it's rather an efford to understand the hierarchy.


Or is it ? Trouble already starts here, I think hmatrix actually implements * on matrices as element-wise multiplication. That's more horrible than Matlab!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM