I've just started learning Haskell, and was surprised by the behaviour of ranges.
I am aware that [1, 2 .. 10]
is syntactic sugar for enumFromThenTo 1 2 10
.
From other programming languages, (for instance Python) I'm used to ranges being specified with first, last and step arguments, such that Haskell's then is equivalent to first+step in Python.
Why does Haskell use then, rather than step to define the spacing between values in the sequence?
Note that e.g. Python's range specifier is a function:
>>> range(1, 12, 2)
[1, 3, 5, 7, 9, 11]
Haskell is aiming to provide syntax that literally looks like you might write out the list for another human, writing ..
instead of the "obvious" pattern:
ghci> [1, 3 .. 11]
[1,3,5,7,9,11]
Another point (raised by Carl in a comment on leftaroundabout's answer) is that the sequence syntax can be used on non-numeric types, where there isn't such an easy way of writing a "step":
ghci> ['a', 'f' .. 'z']
"afkpuz"
Just building on what Ben and Carl said:
the functions defined in Enum are polymorphic, e.g.
λ> :t enumFromThenTo
enumFromThenTo :: Enum a => a -> a -> a -> [a]
and by defining them as "first, second, last", we can use the same polymorphic type parameter a
for all the arguments!
If we defined them as "first, last, step", then the step
parameter might have a different type from the other two.
step
to be some integral type? (But which one?)So we'd need (I think!) to add another type variable to the Enum typeclass, which would make it a lot more complex, and (probably - haven't checked) needs a GHC extension rather than standard Haskell.
I agree, IMO start-step-end would have been the better convention. However, start-then-end is more commonly found in pure maths contexts, and that's Haskell's heritage.
Note that you can very easily achieve by hand
Start-step-end:
takeWhile (<end+step/2) $ iterate (+step) start
Start-step-count:
take count $ iterate (+step) start
Whereas start-then-end requires to first compute the step by hand
let step = then - start
in takeWhile (< end+step/2) $ iterate (+step) start
so it kind of makes sense to add syntactic sugar / standard functions for the expression that's harder to implement manually.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With