【问题标题】:Why does this function crash LispWorks?为什么这个函数会导致 LispWorks 崩溃?
【发布时间】:2026-01-27 04:05:02
【问题描述】:

当我从 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 1 2 1))

【问题讨论】:

    标签: common-lisp lispworks


    【解决方案1】:

    有问题的声明

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

    改为(declare (type (vector number) rowvector))

    错误:列表不是向量

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

    然后该函数使用对FIRSTLAST 的调用,它们不适用于向量,而是列表。

    以更高的safety 值运行代码

    默认情况下不要以低安全性运行 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 2 1) 是一个向量。

    注意:LIST 类型没有参数

    请注意,类型 (list number) 在 Common Lisp 中不存在并且无法定义。 list 类型不能有参数。也不可能基于 cons 类型定义这样的类型 - 递归类型不起作用。

    【讨论】:

      【解决方案2】:

      declare 认为 rowlistvector(但将其视为 list — 使用 lastfirst)。 这意味着编译器假定您传递给它的对象是vector,因此,当您向它传递list 时,您会得到未定义的行为

      关于 Lisp 中的声明,最重要的一点是:不要对编译器撒谎。 即,如果您违反您的声明(就像您刚才所做的那样),您将被烧毁。

      (另外,你不需要evalnil,也不需要let*,因为你只使用了它绑定一次的变量)。

      【讨论】:

      • 它被称为 (should-flip-block '(1 2 1 2 1))。删除 declare 确实解决了问题,但它不会让我 (declare ((list number) rowlist))。
      • @MarkGreen 你能澄清一下你所说的“......它不会让我(declare ((list number) rowlist))”吗?
      • 当我尝试使用该声明代替向量之一时,出现错误 - “不知道如何处理声明”。
      • 哦,我认为这是一个警告。但可能它很糟糕,因为它应该能够对声明做一些事情。
      最近更新 更多