Common lisp 为什么这个函数会使LispWorks崩溃?

Common lisp 为什么这个函数会使LispWorks崩溃?,common-lisp,lispworks,Common Lisp,Lispworks,当我从LispWorks中的侦听器运行此函数时,它要么使侦听器崩溃,要么给出异常和汇编语言数据。有谁能告诉我它有什么问题吗 (defun should-flip-block (rowlist) (declare ((vector number) rowlist)) (if (= (length rowlist) 0) (eval nil) (let* ((exithigh (= (car (last rowlist)) 2)) (enterhigh (=

当我从LispWorks中的侦听器运行此函数时,它要么使侦听器崩溃,要么给出异常和汇编语言数据。有谁能告诉我它有什么问题吗

(defun should-flip-block (rowlist)
  (declare ((vector number) rowlist))
  (if (= (length rowlist) 0) (eval nil) 
    (let* ((exithigh (= (car (last rowlist)) 2))
           (enterhigh (= (first rowlist) 2)))  
      (and exithigh enterhigh))))

它被称为
(should flip block'(1 2 2 1))

声明
行列表
是一个
向量(但它是一个
列表
——使用
最后一个
第一个
)。
这意味着编译器假定您传递给它的对象是一个
向量
,因此,当您传递给它一个
列表
时,您会得到未定义的行为

关于Lisp中的声明,需要知道的最重要的事情是:不要对编译器撒谎。 也就是说,如果你违反了你的声明(就像你刚才做的那样),你会被烧死


(此外,您不需要
eval
nil
,也不需要
let*
,因为您只使用了它绑定的变量一次)。

声明
行列表
向量
(但使用
最后一个
第一个
)。
这意味着编译器假定您传递给它的对象是一个
向量
,因此,当您传递给它一个
列表
时,您会得到未定义的行为

关于Lisp中的声明,需要知道的最重要的事情是:不要对编译器撒谎。 也就是说,如果你违反了你的声明(就像你刚才做的那样),你会被烧死


(此外,您不需要
eval
nil
,也不需要
let*
,因为您只使用了它绑定的变量一次)。

有问题的声明

请注意,并非所有常见的Lisp实现都认为
(declare((vector number))rowvector)
是有效的声明

改为编写
(声明(类型(向量号)行向量))

错误:列表不是向量

您看到的问题是因为您对实现撒谎,并且
安全性设置为低。您告诉Lisp参数是一个向量,但您传递了一个列表(它不是向量)

然后,该函数使用对
FIRST
LAST
的调用,这两个函数对向量无效,但对列表有效

以更高的
安全性运行代码

默认情况下,不要在安全性较低的情况下运行Common Lisp。使用默认安全值2或3

使用LispWorks 6.1.1:

CL-USER 43 > (proclaim '(optimize (safety 2)))
NIL
现在我重新编译函数,然后调用它:

CL-USER 44 > (should-flip-block '(1 2 1 2 1))

Error: Variable ROWLIST was declared type (VECTOR NUMBER) but is being
       bound to value (1 2 1 2 1)
  1 (abort) Return to level 0.
  2 Return to top loop level 0.
现在您看到了一个有用的错误,而不是段冲突

文字向量

#(1 2 1)
是一个向量

注意:
列表
类型没有参数


请注意,Common Lisp中不存在类型
(列表编号)
,因此无法定义。类型
列表
不能有参数。基于类型
cons
也无法定义这样的类型-递归类型不起作用。

有问题的声明

请注意,并非所有常见的Lisp实现都认为
(declare((vector number))rowvector)
是有效的声明

改为编写
(声明(类型(向量号)行向量))

错误:列表不是向量

您看到的问题是因为您对实现撒谎,并且
安全性设置为低。您告诉Lisp参数是一个向量,但您传递了一个列表(它不是向量)

然后,该函数使用对
FIRST
LAST
的调用,这两个函数对向量无效,但对列表有效

以更高的
安全性运行代码

默认情况下,不要在安全性较低的情况下运行Common Lisp。使用默认安全值2或3

使用LispWorks 6.1.1:

CL-USER 43 > (proclaim '(optimize (safety 2)))
NIL
现在我重新编译函数,然后调用它:

CL-USER 44 > (should-flip-block '(1 2 1 2 1))

Error: Variable ROWLIST was declared type (VECTOR NUMBER) but is being
       bound to value (1 2 1 2 1)
  1 (abort) Return to level 0.
  2 Return to top loop level 0.
现在您看到了一个有用的错误,而不是段冲突

文字向量

#(1 2 1)
是一个向量

注意:
列表
类型没有参数


请注意,Common Lisp中不存在类型
(列表编号)
,因此无法定义。类型
列表
不能有参数。基于类型
cons
,也不可能定义这样的类型-递归类型不起作用。

它被称为(应翻转块’(1 2 1))。删除declare确实解决了问题,但它不允许我(declare((列表编号)rowlist))。@MarkGreen您能澄清一下您所说的“…它不允许我
(declare((列表编号)rowlist))
”是什么意思吗?当我尝试使用该declare代替矢量一时,我得到一个错误——“不知道如何处理声明”。噢,我认为这是一个警告。但这可能是不好的,因为它应该能够对声明做一些事情,它被称为(shouldlipblock'(1-2-1))。删除declare确实解决了问题,但它不允许我(declare((列表编号)rowlist))。@MarkGreen您能澄清一下您所说的“…它不允许我
(declare((列表编号)rowlist))
”是什么意思吗?当我尝试使用该declare代替矢量一时,我得到一个错误——“不知道如何处理声明”。噢,我认为这是一个警告。但这大概是不好的,因为它应该能够对声明做些什么。