减少 Common Lisp 中的循环列表
Reducing a circular list in Common Lisp
我一直在使用 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*)
现在再也不会 returns。
但是当我尝试时
CL-USER> (reduce #'+ *foo* :end 3)
...
我也有一个无限循环。
为什么会这样?有没有办法在不显式使用的情况下解决这个问题
循环结构如 LOOP
或 DO
?我正在使用 SBCL,但尝试使用其他实现(CLISP、ECL),它们都有同样的问题。
我同意您观察到的行为可以作为一个开始 - 毕竟,为什么不处理循环列表的前 3 个元素?
让我们阅读一下 ANSI Common Lisp 标准:
- 异常情况:如果序列不是[=38],应该准备好发出
type-error
类型的错误信号 =]正确的顺序。
- 不是不正确列表的序列;也就是说,一个向量或一个适当的列表。
- 不是正确列表的列表:循环列表或点列表。
Should be prepared to signal an error:
- 始终允许实现发出错误信号,但即使在安全代码中,也只需要在未能发出错误信号时发出错误信号,否则可能会导致错误结果。在不安全的代码中,后果是不确定的。
所以,
- 发出错误信号是 conforming
- 返回
3
也符合要求
- 您的代码是 not conforming - 因为其结果无法通过阅读标准来确定
- 如果我们考虑交互式 (REPL) 代码 safe,则无限循环不 符合
- 如果我们认为 REPL 代码不安全,则无限循环符合要求
就我个人而言,我认为交互式代码应该被视为安全的,所以这是一个错误。 YMMV.
我一直在使用 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*)
现在再也不会 returns。
但是当我尝试时
CL-USER> (reduce #'+ *foo* :end 3)
...
我也有一个无限循环。
为什么会这样?有没有办法在不显式使用的情况下解决这个问题
循环结构如 LOOP
或 DO
?我正在使用 SBCL,但尝试使用其他实现(CLISP、ECL),它们都有同样的问题。
我同意您观察到的行为可以作为一个开始 - 毕竟,为什么不处理循环列表的前 3 个元素?
让我们阅读一下 ANSI Common Lisp 标准:
- 异常情况:如果序列不是[=38],应该准备好发出
type-error
类型的错误信号 =]正确的顺序。
- 不是不正确列表的序列;也就是说,一个向量或一个适当的列表。
- 不是正确列表的列表:循环列表或点列表。
Should be prepared to signal an error:
- 始终允许实现发出错误信号,但即使在安全代码中,也只需要在未能发出错误信号时发出错误信号,否则可能会导致错误结果。在不安全的代码中,后果是不确定的。
所以,
- 发出错误信号是 conforming
- 返回
3
也符合要求 - 您的代码是 not conforming - 因为其结果无法通过阅读标准来确定
- 如果我们考虑交互式 (REPL) 代码 safe,则无限循环不 符合
- 如果我们认为 REPL 代码不安全,则无限循环符合要求
就我个人而言,我认为交互式代码应该被视为安全的,所以这是一个错误。 YMMV.