我在sbcl 1.1.14中試過下面的代碼,但是看起來類型檢查忽略了向量元素的聲明。如何在sbcl(或common lisp)向量中指定元素類型?
(defun test (vec)
(declare (type (vector integer) vec))
(format nil "~a~&" (elt vec 0)))
任何提示?謝謝!
我在sbcl 1.1.14中試過下面的代碼,但是看起來類型檢查忽略了向量元素的聲明。如何在sbcl(或common lisp)向量中指定元素類型?
(defun test (vec)
(declare (type (vector integer) vec))
(format nil "~a~&" (elt vec 0)))
任何提示?謝謝!
請注意,首先將聲明作爲類型檢查不是由標準ANSI Common Lisp提供的。這是CMUCL引入的一個擴展。 SBCL是CMUCL的後代。
Common Lisp類型系統適用於向量和數組的方式稍有不同。
元素類型。
正在使用元素類型創建數組。這意味着Lisp系統將創建一個可以存儲該類型元素的數組。但Common Lisp並不要求每個元素類型都有專門的數組版本。如果數組的特定版本不可用,那麼元素類型將升級爲下一個「更大」類型。
示例元素類型升級
CL-USER 14 > (upgraded-array-element-type '(unsigned-byte 1))
(UNSIGNED-BYTE 1)
CL-USER 15 > (upgraded-array-element-type '(unsigned-byte 2))
(UNSIGNED-BYTE 2)
所以存在用於(unsigned-byte 1)
和(unsigned-byte 2)
優化陣列的版本。
CL-USER 16 > (upgraded-array-element-type '(unsigned-byte 3))
(UNSIGNED-BYTE 4)
OOPS!沒有針對(unsigned-byte 3)
進行優化的陣列。如果你要求這樣一個數組,你會得到一個稍大的數組,對於(unsigned-byte 4)
。
CL-USER 17 > (upgraded-array-element-type '(unsigned-byte 4))
(UNSIGNED-BYTE 4)
CL-USER 18 > (upgraded-array-element-type '(unsigned-byte 5))
(UNSIGNED-BYTE 8)
CL-USER 19 > (upgraded-array-element-type 'integer)
T
上面顯示沒有整數的特殊數組。你會得到一個通用數組。
代碼
(defun test (vec)
(declare (type (vector integer) vec))
(format nil "~a~&" (elt vec 0)))
所以在這裏你的宣言的真正含義是:
變量vec
勢必能舉行integer
數字的載體。
,這並不意味着:
可變vec
綁定到其中僅helds integer
號的向量。在我的Lisp
CL-USER 21 > (typep '#(a "b" #\c) '(vector integer))
T
以上返回true,因爲向量是一個普遍的載體,它可以存儲整數。所以它檢查向量的類型,但它並不關心向量的內容實際上是否都是整型。它只是說,矢量可以包含整數。
基於謂詞型檢查
Common Lisp的允許類型聲明使用謂詞。
CL-USER 28 > (defun vector-of-numbers-p (vector)
(and (typep vector 'vector)
(every 'integerp vector)))
VECTOR-OF-NUMBERS-P
CL-USER 29 > (typep '#(a "b" #\c) '(satisfies arrayp))
T
CL-USER 30 > (typep '#(a "b" #\c) '(satisfies vector-of-numbers-p))
NIL
CL-USER 31 > (typep '#(1 2 3) '(satisfies vector-of-numbers-p))
T
但在編譯時檢查?可能不會。
非常感謝!非常明確和翔實的解釋。我現在更瞭解陣列。這真的不直截了當。這種設計很有趣,儘管通常需要具有一種特定類型的元素的數組(矢量),至少對於科學計算來說。希望普通的lisp可以提供專門用於任何類型的數組。 – user3185284
@ user3185284:這是如何需要的?什麼樣的科學需要它?請注意,_type_可以是「所有素數」或「至少有4個門的所有紅色汽車」。也許你正在考慮_classes_? – Svante
您可以詳細說明您的意思嗎*類型檢查忽略聲明*?當我運行你的代碼並執行'(test#(1 2 3))'時,我得到了'1'。當我做'(test'(1 2 3))''我得到'值(1 2 3)不是類型(VECTOR INTEGER).'正如所料。我正在使用'sbcl'版本1.0.57。 – lurker
@mrbatch嘗試(測試#('1 2 3))返回'1沒有警告/錯誤對我來說(SBCL 1.1.14) – verdammelt
@verdammelt啊是的,我明白了。還有'(test#(a b c))'不會返回錯誤,只是'A' – lurker