6

至少 Common Lisp 的某些实现不允许用户定义的常量在某些类型说明符中用作数组维度。例如,在 SBCL 中,此代码:

(defconstant +len+ 3)

(defun foo (x) 
  (declare (type (simple-array fixnum (+len+)) x))
  x)

生成此错误:

; in: DEFUN FOO
;     (TYPE (SIMPLE-ARRAY FIXNUM (+LEN+)) X)
; 
; caught ERROR:
;   bad dimension in array type: +LEN+

为什么?用户定义的常量不能在类型说明符中使用似乎令人惊讶,因为希望能够使用某种全局定义来协调多个类型说明符。我知道类型说明符需要在编译时完全可以理解。但我原以为编译器能够替换用defconstant其文字值定义的符号。我会认为这是defconstant. (到目前为止,我一直未能从 Common Lisp Hyperspec、CLTL2、SBCL 手册或谷歌提供的内容中更深入地理解这个问题。我怀疑答案是以某种形式存在的......)

4

5 回答 5

6

我想这样的事情会起作用:

(defconstant +len+ 3)

(deftype len-3-fixnum-array () `(array fixnum (,+len+)))

(defun foo (x)
  (declare (type len-3-fixnum-array x))
  (print x))

(foo (make-array 3 :element-type 'fixnum))
;; #(0 0 0)

(foo (make-array 4 :element-type 'fixnum))
;; The value #(0 0 0 0) is not of type (VECTOR FIXNUM 3).
;;    [Condition of type TYPE-ERROR]

但是,您需要记住,类型注释只是建议,编译器可以完全忽略它们。


即问题不在于您不能在declare表单中使用常量,而在于它的行为就像它被引用一样,因此您的常量不会评估为 3,它只是保留符号+len+

于 2013-09-30T06:55:53.230 回答
6

我对二维数组有同样的问题:

(defconstant board-width  4)
(defconstant board-height 3)

(setq *board* (make-array '(board-width board-height) :initial-element 0))

我总是收到错误

The value BOARD-WITH is not of type SB-INT:INDEX.

所以我以这种方式更改了最后一行:

(setq *board* (make-array (list board-width board-height) :initial-element 0))

它工作得很好。

于 2015-12-01T12:35:43.157 回答
5

如果您查看 ANSI CL 规范,就会清楚地定义类型的语法。对于简单数组

simple-array [{element-type | *} [dimension-spec]]

dimension-spec::= rank | * | ({dimension | *}*) 

在哪里:

dimension---a valid array dimension.

element-type---a type specifier.

rank---a non-negative fixnum.

然后valid array dimension将其解释为fixnum。

simple-array类型声明中没有变量或常量标识符。类型声明有它们自己的语法并且不被评估或类似。它们是可以出现在代码中特殊位置(-> 声明)的类型表达式。

不过,您可以使用DEFTYPE创建新的类型名称并使用它们。

于 2013-09-30T06:56:07.570 回答
4

好吧,因为似乎没有人真正给出提问者需要的东西,所以这里是:

(defun foo (x) 
  (declare (type (simple-array fixnum (#.+len+)) x))
  x)

#.是一个标准的读取宏,用于评估读取时间中的值。Lisp 形式只看到扩展的内容。http://www.lispworks.com/documentation/HyperSpec/Body/02_dhf.htm

于 2019-04-19T12:18:28.507 回答
3

其他两个答案告诉您如何解决限制以及标准中指定限制的位置

我会试着告诉你这个限制是从哪里来的

原因是 Lisp 声明不仅旨在作为人类读者的代码文档,而且还旨在帮助编译器优化代码。即,数组大小在声明时应允许编译器在必要时分配固定大小的数组,并推断数组索引的存储要求。它类似于C禁止类似代码的限制

int N = 10;
int v[N];

当您开始查看编译器 POV 中的声明时,需求将变得非常自然。

于 2013-09-30T13:23:36.347 回答