Why is the Haskell range syntax using First and Then rather than First and Step?

I was just starting to learn Haskell and was surprised by the behavior of ranges.

I know that [1, 2 .. 10] is syntactic sugar for enumFromThenTo 1 2 10 .

From other programming languages ​​(like Python), I use ranges specified with the first, last, and step arguments, so Haskell is then equivalent to the first + step in Python.

Why does Haskell use a step instead to determine the spacing between values ​​in a sequence?

+7
haskell range
source share
3 answers

Note that, for example, the Python Range Specifier is a function:

 >>> range(1, 12, 2) [1, 3, 5, 7, 9, 11] 

Haskell aims to provide syntax that literally looks as if you could write a list for another person by writing .. instead of the "obvious" template:

 ghci> [1, 3 .. 11] [1,3,5,7,9,11] 

Another point (raised by Carl in the comment to the answer on the left) is that the sequence syntax can be used for non-numeric types, where there is no such easy way to write a "step":

 ghci> ['a', 'f' .. 'z'] "afkpuz" 
+8
source share

Just based on what Ben and Karl said:

functions defined in Enum are polymorphic, for example

 Ξ»> :t enumFromThenTo enumFromThenTo :: Enum a => a -> a -> a -> [a] 

and defining them as "first, second, last", we can use the same parameter of the polymorphic type a for all arguments!

If we defined them as "first, last, step", then the parameter step may have a different type from the other two.

  • For an integer sequence, the step is also an integer - no problem.
  • For a sequence of characters, the step is again an integer - so maybe we could fix the type step as an integral type? (But which one?)
  • But no - for a sequence with floats, this step should also be floating!

So, we need (I think!) To add another type variable to the Enum class, which would make it a lot more complicated, and (probably not tested) requires a GHC extension, not a standard Haskell.

+5
source share

I agree, starting an IMO inception phase would be a better deal. However, start-then-end is more common in a pure mathematical context and in the Haskell legacy.

Please note that you can easily reach manually.

  • Start-step end:

     takeWhile (<end+step/2) $ iterate (+step) start 
  • Start-up quantity:

     take count $ iterate (+step) start 

While for the beginning-end you must first calculate the step manually

 let step = then - start in takeWhile (< end+step/2) $ iterate (+step) start 

therefore, it makes sense to add syntactic sugar / standard functions for an expression that is more difficult to implement manually.

+4
source share

All Articles