Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Does Haskell's Range Syntax use First and Then rather than First and Step?

Tags:

range

haskell

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?

like image 492
Joe Avatar asked Mar 14 '17 14:03

Joe


3 Answers

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"
like image 66
Ben Avatar answered Oct 21 '22 23:10

Ben


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.

  • For an integer sequence, the step is also an integer - no problem.
  • For a character sequence, the step is again an integer - so maybe we could fix the type of step to be some integral type? (But which one?)
  • But no - for a float sequence, the step also needs to be a float!

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.

like image 30
DNA Avatar answered Oct 21 '22 22:10

DNA


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.

like image 4
leftaroundabout Avatar answered Oct 21 '22 23:10

leftaroundabout