0

My question is why Float is not readily defined to be an instance of the Monoid type class ? I mean what is against it ? Doesn't Floats have the identity element and if no why? Also the operations (*) and (+) are associative in the set of Floats, or ?

IPiiro
  • 97
  • 1
  • 9
  • Well the question actually already partially contains the answer: what operation will you pick? There is no inherent better one. `Monoid` is defined for types where it makes sense to have a straight forward "correct" operation. – Willem Van Onsem Jul 20 '17 at 10:47
  • So because you could pick `(*)` and `(+)` as operation for it, it makes no sense ? Excuse me but I kinda don't really understand the problem – IPiiro Jul 20 '17 at 10:53
  • 1
    @IPirro: the problem is that you can only define *one* instance per type. So if you pick `(+)`, you cannot pick `(*)` and vice versa. In mathematics, a monoid is a 3-tuple: `(S,+,e)` with `S` the set, `+` the operation, and `e` the identity. But there can be multiple monoids with the same set, operation and/or identity element. – Willem Van Onsem Jul 20 '17 at 10:56
  • 1
    Ok so just to be correct, Integer and Double wouldn't also not be instances of the Monoid class ? Oh alright that explanation is good – IPiiro Jul 20 '17 at 10:58
  • 1
    based on the query `:i Monoid`, I get that `[a]`, `Ordering`, `Maybe a`, and `a -> b` are monoids (as well as tuples given the elements of the tuples are monoids). So indeed, `Integer` is not a monoid. – Willem Van Onsem Jul 20 '17 at 10:59
  • @IPiiro: It's the same as with _Int_ or _Integer_. The reasons why _Int_ has no default Monoid instance is mentioned in every tutorial on Monoids. – Jogger Jul 22 '17 at 09:31

1 Answers1

6

Which monoid is are you talking about? Sum? Product?

These are already available by wrapping the type with the newtype Sum or Product. But you are correct that addition and multiplication are not associative for floating-point numbers. That's somewhat a different issue, however. The issue is that there's not an obvious "correct" monoid to choose by default.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • I know addition isn't associative for floating-point. Why isn't multiplication? Something about normalization or NaN? – dfeuer Jul 20 '17 at 18:35
  • 2
    @dfeuer Consider something like `(x*y)*(1/y)`, compared to `x*(y*(1/y))`, where `x*y` is too large to fit in a float (ie, evaluates to Infinity). After you get to Infinity, dividing by y no longer gets you back to x. There are probably similar issues when `x*y` is simply large enough to lose the precision that `x` alone had, so that when you divide by `y` again you can't get back all the information `x` had, even though you land in the same neighborhood. – amalloy Jul 20 '17 at 19:57
  • 1
    @dfeuer: Also, rounding will cause `x*(y*z) != (x*y)*z`. – Dietrich Epp Jul 20 '17 at 22:09
  • 1
    I want to emphasize that the decision not to give the numeric types `Monoid` instances is extremely subjective. The haskell ecosystem is by no means consistent if the rule is "only obviously correct instances, else newtype wrapper" `Maybe` and lists for instance both have equally obvious alternatives for instance. – jberryman Jul 20 '17 at 22:10
  • @jberryman: I can understand Maybe but lists are basically the free monoid for sets to begin with. – Dietrich Epp Jul 21 '17 at 04:40