3

I've been playing around with circular list in Common-lisp (SBCL) and encountered the following problem when trying to call REDUCE on such a list.

First, we create a list:

CL-USER> (defvar *foo* (list 1 1 1 1))
*foo*

Of course, now we can do

CL-USER> (reduce #'+ *foo*)
4

or

CL-USER> (reduce #'+ *foo* :end 3)
3

However, if we create a circular list:

CL-USER> (setf *print-circle* t)
CL-USER> (setf (cdr (last *foo*)) *foo*)
CL-USER> *foo*
#1=(1 1 1 1 . #1#)

Obviously (reduce #'+ *foo*) now never returns.

But when I tried

 CL-USER> (reduce #'+ *foo* :end 3)
 ...

I also got an infinite loop.

Why is that so? Is there any way to work around this without explicitly using loop construct such as LOOP or DO? I'm working with SBCL, but tried this with other implementations (CLISP, ECL), they all have the same problem.

Rainer Joswig
  • 127,693
  • 10
  • 201
  • 325
jobach
  • 95
  • 7
  • 2
    Note that if you use [CCL](http://ccl.clozure.com) then `(reduce #'+ *foo* :end 3)` produces `3`, while `(reduce #'+ *foo*)` signal a `[Condition of type CCL::IMPROPER-LIST]`. – Renzo Aug 14 '15 at 15:09
  • So, it should be interesting to know how the different systems check for an “improper list”. Do they examine the whole list *before* processing it? Do they have this information in the type of the list? What it is the correct semantics? (even if today it seems that nobody cares any more for formal semantics of programming languages). – Renzo Aug 14 '15 at 15:16
  • Maybe the SBCL maintainers would accept a patch which would enable SBCL to report such an error? – Rainer Joswig Aug 14 '15 at 15:47

1 Answers1

5

I agree that the behavior you observe can give one a start - after all, why not process the first 3 elements of the circular list?

Let us read the ANSI Common Lisp standard:

reduce:

  • Exceptional Situations: Should be prepared to signal an error of type type-error if sequence is not a proper sequence.

proper sequence:

  • a sequence which is not an improper list; that is, a vector or a proper list.

improper list:

  • a list which is not a proper list: a circular list or a dotted list.

Should be prepared to signal an error:

  • An implementation is always permitted to signal an error, but even in safe code, it is only required to signal the error when failing to signal it might lead to incorrect results. In unsafe code, the consequences are undefined.

So,

  • signaling an error is conforming
  • returning 3 is conforming as well
  • your code is not conforming - since its outcome cannot be determined by reading the standard
  • if we consider the interactive (REPL) code safe, then the infinite loop is not conforming
  • if we consider the REPL code unsafe, then infinite loop is conforming

Personally, I think that interactive code should be viewed as safe, so this is a bug. YMMV.

sds
  • 52,616
  • 20
  • 134
  • 226
  • 2
    What exactly is meant by: "but it is mandated by the ANSI Common Lisp standard"? There's certainly undefined behavior here, and the implementations are free to signal a type-error, even though they don't have to (as we have seen, many don't seem to; similarly for mapcar, etc.). So I entirely agree that the desired behavior is *not* mandated by the standard, but I'm not clear which behavior you are saying *is* mandated. – Joshua Taylor Aug 14 '15 at 15:17
  • 2
    Still, "this behavior (error) is encouraged by the ANSI Common Lisp standard" is actually a bit misleading too, since OP *doesn't* actually get an error, just an (apparent) infinite loop. Some CL implementations do signal an error (as Renzo noted in [a comment](http://stackoverflow.com/questions/32010174/reducing-a-circular-list-in-common-lisp/32012790?noredirect=1#comment51928895_32010174)). It's more like "the situation has undefined behavior, but implementations are free to signal an error, even if your implementation (SBCL) doesn't." – Joshua Taylor Aug 14 '15 at 15:30
  • I suspect that a non-terminating function call doesn't qualify as an "incorrect result" (no value(s) are returned) in standards terms. – Vatine Aug 15 '15 at 12:37
  • I found a related bug to be already reported at https://bugs.launchpad.net/sbcl/+bug/309144 and posted the `REDUCE`/`:END`-issue discussed here as a comment. – jobach Aug 15 '15 at 18:35
  • Non-terminating function does not return the correct result, so it is incorrect. – sds Aug 16 '15 at 04:45