Skip to content

Implementation of `enumFromTo` for `Float` seems confusing in behavior

Summary

The implementation of enumFromThenTo/enumFromTo/etc… evaluates start + k·step for a value k starting at 0, incremented by 1 each step.

For expressions [a :: Float .. b], this results in unexpected behavior when the value k reaches 224, because k itself is a Float as-well. The value 224 is about 16 million, so it can be reached in less than 3 seconds on modern hardware.

Steps to reproduce

Inspect the list [-16000000 :: Float .. 1000000],

e.g. by evaluating take 30 $ dropWhile (< 777210) [-16000000 :: Float .. 1000000]

or trying to determine length [-16000000 :: Float .. 1000000]

Expected behavior

Especially considering that both -16000000 and +1000000 are well withing the range that Float supports on a precision level where every integer is still precisely representable, one would expect that [-16000000 :: Float .. 1000000] is a finite list.

Consequently one would expect length [-16000000 :: Float .. 1000000] to terminate – it doesn’t – and one would expect take 30 $ dropWhile (< 777210) [-16000000 :: Float .. 1000000] to evaluate to

[777210.0,777211.0,777212.0,777213.0,777214.0,777215.0,777216.0,777217.0,777218.0,777219.0,777220.0,777221.0,777222.0,777223.0,777224.0,777225.0,777226.0,777227.0,777228.0,777229.0,777230.0,777231.0,777232.0,777233.0,777234.0,777235.0,777236.0,777237.0,777238.0,777239.0]

– yet it returns

[777210.0,777211.0,777212.0,777213.0,777214.0,777215.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0,777216.0]

Environment

Environment should be irrelevant, the relevant implementation is in https://gitlab.haskell.org/ghc/ghc/-/blob/98aa29d3fe447cce3407e6864b015892244bb475/libraries/base/GHC/Real.hs#L273-L279

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information