减少Common Lisp中的循环列表

时间:2015-08-14 12:30:19

标签: list common-lisp reduce sbcl circular-list

我一直在使用Common-lisp(SBCL)中的循环列表,并在尝试在这样的列表上调用REDUCE时遇到以下问题。

首先,我们创建一个列表:

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

当然,现在我们可以做到

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

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

但是,如果我们创建一个循环列表:

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

显然(reduce #'+ *foo*)现在永远不会回来了。

但是当我尝试

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

我也有一个无限循环。

为什么会这样?有没有办法在没有明确使用的情况下解决这个问题 循环结构,如LOOPDO?我正在使用SBCL,但尝试使用其他实现(CLISP,ECL),它们都有同样的问题。

1 个答案:

答案 0 :(得分:5)

我同意你观察到的行为可以给一个开始 - 毕竟,为什么不处理循环列表的前3个元素?

让我们阅读ANSI Common Lisp标准:

reduce

  • 例外情况:如果序列不是正确的序列,则应准备好发出type-error类型的错误信号

proper sequence

  • 不是不当列表的序列;即,向量或适当的列表。

improper list

  • 不是正确列表的列表:循环列表或虚线列表。

Should be prepared to signal an error

  • 始终允许实现发出错误信号,但即使在安全代码中,也只需要在发出错误信号时发出错误信号,否则可能导致错误结果。在不安全的代码中,后果是不确定的。

所以,

  • 发出错误信号conforming
  • 返回3也符合
  • 您的代码为not conforming - 因为无法通过阅读标准确定其结果
  • 如果我们考虑交互式(REPL)代码safe,那么无限循环符合
  • 如果我们认为REPL代码不安全,那么无限循环就符合

就个人而言,我认为交互式代码应该被视为安全,因此这是一个错误。 YMMV。