简体   繁体   中英

Rationale behind Haskells `succ` on numbers (floats)

I was a bit surprised to learn that Haskell defines its succ function on numbers as adding one:

succ :: a -> a
The successor of a value. For numeric types, succ adds 1 .

Although for integral values, this seems reasonable there are a few problems:

  • what if you define a numeric system that can only represent even/odd/prime/... numbers, in other words a dedicated type that is a subset of integral numbers;
  • if you define some kind of "fixed-point number" that represents half and full numbers, in that case not all numbers are enumerated; and
  • the problem is most severe for floating point numbers .

First of all, it means that [2.0 :: Float .. 3.0 :: Float] (used :: Float to make sure the call is not ambiguous) only contains integral values added to the original value, whereas if one uses this expression he/she might expect the list will include all floating points between the two values; of course this argument is more about what one prefers. Most programmers don't have much problems with this aspect.

More severely, if one uses the expression [2.2 :: Float .. 4.0 :: Float] it results in [2.2,3.2,4.2] what is 4.2 doing here?

If one uses a floating point number where +1 cannot generate a different number (because the mantissa doesn't have enough bits to represent one anymore), it will loop infinitely. For instance:

Prelude> [1e37 :: Float .. 1e37 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. 1e37-1 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. 1e37+1 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.
Prelude> [1e37 :: Float .. pred 1e37 :: Float]
[1.0e37,1.0e37,1.0e37,1.0e37,1.0e37,1^C.0e37,Interrupted.

One thus generates an infinite amount of values, even if the list ought to be empty or contain a few elements.

Part of the arguments are indeed a bit nitpicking, but at least for some, it is reasonable to assume that a Haskell programmer will eventually make mistakes.

Wouldn't a more reasonable approach have been to generate the next representable floating point number?

What were the arguments to define succ in such way? Is it reasonable that Float is an instance of Enum ?

The origin of the succ function itself actually has nothing to do with the Haskell data types or enumerations, in fact the succ function came first. The succ function is actually the successor function in the axiom of infinity which allows us to create numbers in the first place . It was never designed to be used with floating point/non-natural numbers, that's why you're encountering this problem.

It would probably be a good idea to modify the succ function for floating point types in Haskell, you ought to submit something to the mailing list about it. Although, Haskell is standardized in the Haskell98 report so don't get your hopes up about changing the language.

Only read the following if you are familiar with Haskell's type classes: You mention different possible uses of the succ function, this is why it is defined as a function for the Enum type class. Therefore you can easily rebind it to do something different with a newtype .

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