[erlang-questions] lists:seq/[2,3] bug?
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.
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).
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  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:
> 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) ->
> seq_loop(0, _, 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
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 ;-)
More information about the erlang-questions