10

Not long ago I've discovered Natural data type in base. It's supposed to be taken (as it seems to me) when you intend to use non-negative integer type. But it's not exactly clear why should I prefer Natural to Integer. Both types have arbitrary precision, both have quite optimized runtime representation — Integer representation and Natural representation. But Natural can throw pure exceptions when you subtract natural numbers and this doesn't really add more typesafety to your code. While Integer is more popular across all packages.

So when and why should I use Natural?

Shersh
  • 9,019
  • 3
  • 33
  • 61
  • 1
    This could be a bit opinionated, but my criterion would be "if you'd prefer a runtime error to a negative result, choose `Natural`" – chi Aug 27 '17 at 12:52
  • @chi Agree. While we have `negate` and `(-)` inside `Num` type class not much we can do to not allow subtractions. – Shersh Aug 27 '17 at 13:41

1 Answers1

6

I do not see why you want to use Natural or Integer. Why not use Rational instead? It is arbitrary precision, has an optimised runtime representation, and works for naturals, integers, and rationals!

My point is that we should choose a type which makes sense semantically. Lets count the houses on the street with naturals, record our next golf game with integers, and divide a fresh blueberry pie with rationals.

erisco
  • 14,154
  • 2
  • 40
  • 45
  • I don't know what parts (if any) of this are meant sarcastically. I think you should better write clearly what your opinion is. – leftaroundabout Aug 27 '17 at 13:10
  • @leftaroundabout I encourage you to add a second answer in a different rhetorical style. – erisco Aug 27 '17 at 13:29
  • @erisco The reason to pick `Natural` because of semantic sense is a good reason. But then: why not `newtype Natural = Natural Integer`? `Rational` is much-much slower than `Integer` or `Natural` because of constant calls to `gcd` function. But it's not clear which one — `Natural` or `Integer` — is slower because of compiler optimizations and inlining and all that stuff. My question is not just «duh, I have two types, emm... what should I use? I'm so stupid, I can't choose». But why create such `Natural` type with such semantic. Why exception instead saturation? What benefits I can gain? – Shersh Aug 27 '17 at 13:39
  • @erisco I don't have a clear opinion on this yet that I could could write. Haskell traditionally does not distinguish positive and general integers through the type system and has fared pretty well with it. I furthermore tend to use only integers that could actually adress/index something in memory, and fast, hence my go-to type is actually `Int`. But that's not to say I don't see why it might make sense to opt for `Integer` or indeed `Natural` in some applications, I just don't know when this is worth it. – leftaroundabout Aug 27 '17 at 13:48
  • @Shersh you offered good reasons based on the implementation of `Integer` and `Natural` to be unconvinced that `Natural` has a use. I have no reason or interest to argue with that. You broadly asked "when and why" to use Natural, however, and so I gave the reason I think is important. This reason has nothing to do with implementation. I have no reason against `newtype Natural = Natural Integer`. The benefit to me is semantics, not the implementation. – erisco Aug 27 '17 at 13:56
  • @erisco Why does Haskell itself then not stick to semantically sensible choices? E.g. `:t length` shows that its result type is `Int` and not `Natural`. That can be annoying if you yourself want to stick to semantically sensible choices. What is the motivation behind the typing of `length`? – wstomv Jun 02 '21 at 19:49
  • @TomVerhoeff The motivation for using `Int` is that 32-bit signed integer operations are much faster on most CPUs. You can use `genericLength` otherwise. – erisco Jun 02 '21 at 21:50