For the record, I'm a Haskell noob. I'm trying to understand why a range can be declared as
[1..10] -- yields [1,2,3,4,5,6,7,8,9,10]
and not
[10..1] -- yields []
It seems simple enough to implement it like this:
(.:.) :: Enum a => a -> a -> [a]
(.:.) a b =
| a == b = []
| a > b = a : (a - 1) .:. b
| a < b = a : (a + 1) .:. b
What am I not understanding here?
Try [10,9..1]
instead of [10..1]
[10..1]
desugars to enumFromTo
[10,9..1]
desugars to enumFromThenTo
Observe how the functions behave in GHCI:
Prelude> [10..1]
[]
Prelude> [10,9..1]
[10,9,8,7,6,5,4,3,2,1]
Prelude> :t enumFromTo
enumFromTo :: Enum a => a -> a -> [a]
Prelude> :t enumFromThenTo
enumFromThenTo :: Enum a => a -> a -> a -> [a]
Prelude> enumFromTo 10 1
[]
Prelude> :t enumFromThenTo 10 9 1
[10,9,8,7,6,5,4,3,2,1]
The new behavior that you implemented in (.:.)
will rarely be a desirable default, as lists generated this way can no longer always be assumed to be in ascending order. Hence the necessity to make your descending intention explicit with [x,(pred x)..y]
or enumFromThenTo
.
Almost always when you have an expression like [1..n]
, and n
happens to be 0, you want the value to be []
rather than [1,0]
. For example consider
factorial n = product [1..n]
Then we want
factorial 0 ~~> product [1..0] ~~> product [] ~~> 1 -- correct
not
factorial 0 ~~> product [1..0] ~~> product [1,0] ~~> 0 -- oops
That's why [m..n]
does not produce a descending list when m > n
.
(If m >= n+2
(for example if in [1..n]
, n
is negative) then it's quite likely an error condition and arguably [m..n]
ought to be an error; but it's still defined by the language standard to be []
.)
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