Odd list comprehension behaviour

Hello, I noticed some odd behaviour with list comprehensions. [1..1] == [1] BUT [1,1..1] == [1..] I noticed this while writing a Clean program, but it seems Haskell inherited this as well. In the case of integer lists with step size >= 0 the up_list function[1] is used: up_list :: Integer -> Integer -> Integer -> [Integer] up_list x0 delta lim = go (x0 :: Integer) where go x | x > lim = [] | otherwise = x : go (x+delta) In the case of [1,1..1] x0 == lim, so go will recurse infinitely, producing an infinite list. I think the reasonable behaviour would be [1,1..1] == [1]. Is there a reason it doesn't work like this? [1] http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li... Thanks, Krisztián

The syntax [a, b..c] in general produces a list which starts with “a", followed by “b", going up until reaching (possibly including) c in step sizes of (b - a). (For simplicity’s sake, I only described non-decreasing lists) So it is logical that a step size of 0 produces an infinite list, when [1,1..1] is given. Notice that [1,1..1] is not the same as [1..], but "repeat 1”. Csongor
On 17 Mar 2016, at 02:58, Krisztian Pinter
wrote: Hello,
I noticed some odd behaviour with list comprehensions.
[1..1] == [1] BUT [1,1..1] == [1..]
I noticed this while writing a Clean program, but it seems Haskell inherited this as well. In the case of integer lists with step size >= 0 the up_list function[1] is used:
up_list :: Integer -> Integer -> Integer -> [Integer] up_list x0 delta lim = go (x0 :: Integer) where go x | x > lim = [] | otherwise = x : go (x+delta)
In the case of [1,1..1] x0 == lim, so go will recurse infinitely, producing an infinite list.
I think the reasonable behaviour would be [1,1..1] == [1]. Is there a reason it doesn't work like this?
[1] http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li... http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li...
Thanks, Krisztián _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

This can be seen with [1,1..2], [1,1..3], etc.
On Wed, Mar 16, 2016 at 8:10 PM, Kiss Csongor
The syntax [a, b..c] in general produces a list which starts with “a", followed by “b", going up until reaching (possibly including) c in step sizes of (b - a). (For simplicity’s sake, I only described non-decreasing lists)
So it is logical that a step size of 0 produces an infinite list, when [1,1..1] is given. Notice that [1,1..1] is not the same as [1..], but "repeat 1”.
Csongor
On 17 Mar 2016, at 02:58, Krisztian Pinter
wrote: Hello,
I noticed some odd behaviour with list comprehensions.
[1..1] == [1] BUT [1,1..1] == [1..]
I noticed this while writing a Clean program, but it seems Haskell inherited this as well. In the case of integer lists with step size >= 0 the up_list function[1] is used:
up_list :: Integer -> Integer -> Integer -> [Integer] up_list x0 delta lim = go (x0 :: Integer) where go x | x > lim = [] | otherwise = x : go (x+delta)
In the case of [1,1..1] x0 == lim, so go will recurse infinitely, producing an infinite list.
I think the reasonable behaviour would be [1,1..1] == [1]. Is there a reason it doesn't work like this?
[1] http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li...
Thanks, Krisztián _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

If you actually evaulate [1,1..1] == [1..] in a GHCI prompt it will tell you False immediately. :) [1..] evaluates to [1, 2, 3, 4, 5, 6, ... etc ... [1,1..1] evaluates to [1, 1, 1, 1, 1, 1 ... etc ... The syntax where you give 2 elements before the .. is intended to resemble this style of shorthand for lists: [1, 2, 3, 4, ...10]. The idea is that Haskell should take the two elements as "example elements" showing the pattern you want. So [1,1..] is saying you want a list that starts at 1, then has 1, and continues on like that; you're specifying a step size of *zero*, not of 1. You can step 1 by 0 an infinite number of times without exceeding 1, so [1,1..1] should not be finite. -- Ben ----- Original Message ----- From: "Krisztian Pinter" To: Cc: Sent:Thu, 17 Mar 2016 03:58:06 +0100 Subject:[Haskell-cafe] Odd list comprehension behaviour Hello, I noticed some odd behaviour with list comprehensions. [1..1] == [1]BUT[1,1..1] == [1..] I noticed this while writing a Clean program, but it seems Haskell inherited this as well.In the case of integer lists with step size >= 0 the up_list function[1] is used: up_list :: Integer -> Integer -> Integer -> [Integer]up_list x0 delta lim = go (x0 :: Integer) where go x | x > lim = [] | otherwise = x : go (x+delta) In the case of [1,1..1] x0 == lim, so go will recurse infinitely, producing an infinite list. I think the reasonable behaviour would be [1,1..1] == [1]. Is there a reason it doesn't work like this? [1] http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li... [1] Thanks,Krisztián Links: ------ [1] http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.Enum.html#up_li...

On Thu, Mar 17, 2016 at 03:58:06AM +0100, Krisztian Pinter wrote:
Hello,
I noticed some odd behaviour with list comprehensions.
[1..1] == [1] BUT [1,1..1] == [1..]
Hello Krisztian, from the Haskell report (enumFromThenTo is longhand for [a,b..c] notation) [1]: The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1+i,e1+2i,...e3], where the increment, i, is e2-e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3. The important bit being "the list terminates when the next element would be greater than e3". Unfortunate in my opinion (I agree with you the fact that `[1..1] /= [1,1..1]` is puzzling), but specs compliant -F [1] https://www.haskell.org/onlinereport/basic.html

On Wed, Mar 16, 2016 at 10:56 PM, Francesco Ariis
from the Haskell report (enumFromThenTo is longhand for [a,b..c] notation) [1]:
The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1+i,e1+2i,...e3], where the increment, i, is e2-e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3.
The important bit being "the list terminates when the next element would be greater than e3". Unfortunate in my opinion (I agree with you the fact that `[1..1] /= [1,1..1]` is puzzling), but specs compliant
I'm not necessarily proposing this, but would it not be also reasonable for this to read "the list terminates when the current element equals e3 or the next element would be greater than e3"? It's slightly more wordy, but it captures the intuition that [a,b..c] ends at c.

On 17/03/16 5:27 pm, Manuel Gómez wrote:
I'm not necessarily proposing this, but would it not be also reasonable for this to read "the list terminates when the current element equals e3 or the next element would be greater than e3"? It's slightly more wordy, but it captures the intuition that [a,b..c] ends at c.
From experience in other programming languages, I don't have that intuition. Indeed, from experience in Haskell, I don't expect [a,b..c] to end at c. [1,3..6] ends at 5, not 6.

On 17/03/16 5:27 pm, Manuel Gómez wrote: I'm not necessarily proposing this, but would it not be also reasonable for this to read "the list terminates when the current element equals e3 or the next element would be greater than e3"? It's slightly more wordy, but it captures the intuition that [a,b..c] ends at c.
On Thu, Mar 17, 2016 at 12:18 AM, Richard A. O'Keefe
From experience in other programming languages, I don't have that intuition. Indeed, from experience in Haskell, I don't expect [a,b..c] to end at c. [1,3..6] ends at 5, not 6.
I apologize — I believe I failed to convey what I tried to say. Perhaps I should instead have said «ends at c at the furthest». The intuition I refer to is that c is a possibly included bound for the list [a,b..c], so that the list [a,b..c] certainly shall not have any element beyond c, but if it does actually get to c, that’s where it ends. In that sense I find it natural that [1,3..6] ends at 5: otherwise it would have elements beyond 6, namely 7. [0,2..6], on the other hand, ends at 6, and indeed does not have any element beyond 6. [6,6..6] would have the initial 6, and then it should have no other element beyond 6, so it should in fact equal [6] under this intuition.

On 17/03/16 7:25 pm, Manuel Gómez wrote:
Perhaps I should instead have said «ends at c at the furthest».
The intuition I refer to is that c is a possibly included bound for the list [a,b..c], so that the list [a,b..c] certainly shall not have any element beyond c, but if it does actually get to c, that’s where it ends.
That's closer to other languages, but the bit "if it does actually get to c, that's where it ends" is smuggled in from somewhere. For cases where a and b are different, you don't *need* that bit; it's easier to understand without the extra cruft. For cases where a and b are equal, it's magic, come from nowhere, just to bodge in a finite answer for one special case. Let me rephrase that. To me, that "if it does actually get to c" bit is NOT a consequence of my understanding of the general rules for enumeration in Haskell, they are a complicating ADDITION to those rules just for a case that I would be very upset to see happening in code of mine. I mean, this is an *extremely* special case. [1.0,1.0..x] :: [Double is an infinite list for ALL x >= 1.0 in Haskell; you want to change this to be [1.0] if x happens to be the very special case 1.0, and I do not understand why. Why is [1.0,1.0..1.0+epsilon] being infinite, [1.0,1.0,..1.0-epsilon] being empty, but [1.0,1.0..1.0] having one element USEFUL? (And while you are at it, explain your reasoning for [x,x..negate x] when x is 0.0.)
[6,6..6] would have the initial 6, and then it should have no other element beyond 6, so it should in fact equal [6] under this intuition.
But [6,6,6,6,6,6,6,6,6,6,6....] ALSO has no other element beyond 6. "Not going beyond 6" is one thing, "stopping exactly at 6" is another.

On Thu, Mar 17, 2016 at 6:47 PM, Richard A. O'Keefe
Let me rephrase that. To me, that "if it does actually get to c" bit is NOT a consequence of my understanding of the general rules for enumeration in Haskell, they are a complicating ADDITION to those rules just for a case that I would be very upset to see happening in code of mine.
Indeed! I agree completely that this is not consistent with the current rules in Haskell, and I agree completely that this is a complicating addition to those rules that is in no way derived from the way things currently work or from some clear greater principle.
I mean, this is an *extremely* special case. [1.0,1.0..x] :: [Double is an infinite list for ALL x >= 1.0 in Haskell; you want to change this to be [1.0] if x happens to be the very special case 1.0, and I do not understand why. Why is [1.0,1.0..1.0+epsilon] being infinite, [1.0,1.0,..1.0-epsilon] being empty, but [1.0,1.0..1.0] having one element USEFUL? (And while you are at it, explain your reasoning for [x,x..negate x] when x is 0.0.)
To be clear: I’m not proposing this, I’m just exploring how such a rule may be specified. Although my current intuition agrees with the original post’s stated intuition in that I was surprised to find [1,1..1] is not finite, I personally don’t think it’s necessarily better to have an intuitive rule: I generally favor rules that are simple to state and reason about, rather than rules that produce superficially intuitive results at the expense of special cases and conceptual complexity — and I certainly hope saying that does not derail this conversation into other recent discussions with similar tradeoffs. ;-) If I were to propose this, which I’m not, I would discuss what the [a,b..c] notation is meant to represent. To me, personally and for no good reason, it looks like an iterator that yields numbers starting at a, adding (b-a) at each step and yielding the next number as long as it’s less than or equal to c, and continuing as long as c is neither reached nor exceeded. I make no claim on the universality of this interpretation or the naturality of its deduction as a result of some prior notational intuition, and I likewise make no claim about the adequacy of this intuition as the foundation for the rules in Haskell. In any case, I would personally never find it reasonable for a proposal to suggest changing the rules Haskell uses to assign meaning to this notation, unless there was very wide community consensus and interest in such a change, which I find doubtful as it’s such a minor detail. I would prefer to see this turn into, say, a very short note in the documentation pointing out this curiosity that may be inconsistent with the intuitive expectations of some of us.
[6,6..6] would have the initial 6, and then it should have no other element beyond 6, so it should in fact equal [6] under this intuition.
But [6,6,6,6,6,6,6,6,6,6,6....] ALSO has no other element beyond 6. "Not going beyond 6" is one thing, "stopping exactly at 6" is another.
I misspoke again, indeed! I should have said «it should have no other element beyond the first 6». Note I also purposely avoided cases with b < a and c < a, as those confuse me even further, and I have no opinion or solid intuition about them.

Arithmetic progressions make *sense* for anything that has "+", whether or not it also has "<". For my Smalltalk system, I ended up with a GenericInterval class with a creation method new: size from: start by: delta. With *that* interface, a delta of zero is perfectly harmless. GenericInterval new: 4 from: 6 by: 0 is (6 6 6 6) and of course GenericInterval new: 1 from: 6 by: 0 is (6) because the new: argument *says* there is to be 1 element. I understand why class Enum doesn't have this kind of interface. Basically, we want to compute [delta*n + start | n <- [0..size-1]] where in cases like duration*n+timestamp delta and start are not the same type. But let's face it, all that means is that if we want this kind of thing, all we have to do is roll our own arithmetic progression functions. Enum has other problems, like its coupling to Int. I find it odd that [1%1,9%8..2%1] works usefully even though fromEnum (1%1) == fromEnum (9%8) == 1. Sensible, just odd.

On Wed, Mar 16, 2016 at 11:57:39PM -0430, Manuel Gómez wrote:
On Wed, Mar 16, 2016 at 10:56 PM, Francesco Ariis
wrote: The important bit being "the list terminates when the next element would be greater than e3". Unfortunate in my opinion (I agree with you the fact that `[1..1] /= [1,1..1]` is puzzling), but specs compliant
I'm not necessarily proposing this, but would it not be also reasonable for this to read "the list terminates when the current element equals e3 or the next element would be greater than e3"? It's slightly more wordy, but it captures the intuition that [a,b..c] ends at c.
Exactly! I am now tempted to fire in haskell-prime.

I haven't found a clear and reasonable example yet, but I am certain that a
non default enumFromThenTo could generate the bound several times (or only
one time), and then later on generate a next that is higher (I think that
modulo arithmetic in enumFromThenTo might do it?). This would certainly be
unorthodox, but it is hypothetically possible. In this case the stop only
when the bound would be exceeded next is more reasonable in my opinion.
Kind regards,
Wilfried van Asten
Op do 17 mrt. 2016 om 06:48 schreef Francesco Ariis
On Wed, Mar 16, 2016 at 11:57:39PM -0430, Manuel Gómez wrote:
On Wed, Mar 16, 2016 at 10:56 PM, Francesco Ariis
wrote: The important bit being "the list terminates when the next element would be greater than e3". Unfortunate in my opinion (I agree with you the fact that `[1..1] /= [1,1..1]` is puzzling), but specs compliant
I'm not necessarily proposing this, but would it not be also reasonable for this to read "the list terminates when the current element equals e3 or the next element would be greater than e3"? It's slightly more wordy, but it captures the intuition that [a,b..c] ends at c.
Exactly! I am now tempted to fire in haskell-prime. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On 17/03/16 3:58 pm, Krisztian Pinter wrote:
I think the reasonable behaviour would be [1,1..1] == [1]. Is there a reason it doesn't work like this? That's arguably *a* reasonable behaviour, but I'm not sure it's *the* reasonable behaviour. Another reasonable behaviour would be a run-time error for [X,X..Y] whatever Y is. And to my mind, what Haskell actually does, while not as programmer-friendly as a run-time error would be, is reasonable because consistent.
In R,
seq(from=1, to=2, by=0) Error in seq.default(from = 1, to = 2, by = 0) : invalid (to - from)/by in seq(.) seq(from=1, to=1, by=0) [1] 1
I find this behaviour in R inconsistent and confusing. At least in Haskell [1,1..N] gives the same answer for any N >= 1.

On Thu, Mar 17, 2016 at 03:58:06AM +0100, Krisztian Pinter wrote:
I noticed some odd behaviour with list comprehensions.
[1..1] == [1] BUT [1,1..1] == [1..]
I think list enumerations are one of those things that would not make it into Haskell today, if we were inventing it from scratch. My (perhaps minority) opinion is that they should be avoided. Tom
participants (9)
-
Ben
-
Francesco Ariis
-
Jesse Frankley
-
Kiss Csongor
-
Krisztian Pinter
-
Manuel Gómez
-
Richard A. O'Keefe
-
Tom Ellis
-
Wilfried van Asten