[erlang-questions] lists:seq/[2,3] bug?

Kostis Sagonas <>
Thu Sep 18 19:20:53 CEST 2008


Richard A. O'Keefe wrote:
> On my Mac I have Erlang R12B-3.
> .....
> 
> lists:seq(1, N) gives me the expected N-element list for
> integers N >= 1.  I expect, indeed, I would require, that
> lists:seq(1, 0) should give me the empty list.

<General_comment>
   The word "expect" is pretty subjective. I think it's better to stick
   to the function's description in the manual before one characterizes
   something as a possible bug.  I am not sure all library users have
   identical (or even similar) expectations, as these depend on their
   experiences, possibly from other languages they are familiar with.
   (Clearly, Richard is as experienced as one can be in this respect).
</General_comment>


The manual reads:

   "seq(From, To) -> Seq
    seq(From, To, Incr) -> Seq

    Returns a sequence of integers which starts with From and contains
    the successive results of adding Incr to the previous element, until
    To has been reached or passed (in the latter case, To is not an
    element of the sequence). Incr defaults to 1."

Hmmm... Had I stopped reading the documentation here, *I* would actually 
expect that lists:seq(1, 0) returns [1] rather than [].  (The phrasing 
"... to the previous element, until ..." suggests a repeat-based rather 
than while-based implementation.)

However, the function's documentation continues:

   "Failure: If To<From and Incr is positive, or if To>From and Incr is
	negative, or if Incr==0 and From/=To."

Since it is stated that "Incr defaults to 1.", then clearly the "If 
To<From and Incr is positive" case applies and an exception is raised.

So, I fail to see why, after having read the manual, one is surprised by 
the results below:

> Instead,
> 
> 2> lists:seq(1, 0).
> ** exception error: no function clause matching lists:seq(1,0)
> 3> lists:seq(1, 0, 1).
> ** exception error: no function clause matching lists:seq(1,0,1)
> 
> Here's a version of seq/2 that does what I expect.
> 
> seq(Min, Max) when is_integer(Min), is_integer(Max), Min-1 =< Max ->
>      seq_loop(Max-Min+1, Max, []).
> 
> seq_loop(N, X, L) when N >= 4 ->
>      seq_loop(N-4, X-4, [X-3,X-2,X-1,X|L]);
> seq_loop(N, X, L) when N >= 2 ->
>      seq_loop(N-2, X-2, [X-1,X|L]);
> seq_loop(1, X, L) ->
>      [X|L];
> seq_loop(0, _, L) ->
>      L.

I agree that it probably does do what you expect it to do, since you are 
the one who wrote it :-)  But then again, what about a call such as 
seq(10, 5) ?  As far as I can see, it raises an exception in this case.

> We expect length(lists:seq(L, U)) == U-L+1.
> It does make sense to report an error when U < L-1,
> because there is no way the result can have negative
> length.  But the empty list is a perfectly good list.
> 
> If people agree that this is a bug I'll provide a version
> of lists:seq/3 that behaves itself.  We do expect that
> lists:seq(L, U) and lists:seq(L, U, 1) will give the
> same answer, after all.

I agree with the last sentence.  But in my opinion, they do have the 
same behaviour:

1> lists:seq(4, 2).
** exception error: no function clause matching lists:seq(4,2)
2> lists:seq(4, 2, 1).
** exception error: no function clause matching lists:seq(4,2,1)

same same, no difference!


Seriously now.  In a statically typed language such as Haskell, I could 
see some good arguments why one would want the lists:seq/[2,3] functions 
to be total and return [] for L > U rather than throwing an exception.
But in a language such as Erlang, I do not see any compelling reason to 
prefer returning []. Then again, perhaps I am not imaginative enough.
I am sure that if there is such a reason, we'll probably soon find out 
about it ;-)


Kostis



More information about the erlang-questions mailing list