Я попробовал следующий код в sbcl 1.1.14, но кажется, что проверка типа игнорирует объявление векторного элемента.
(defun test (vec)
(declare (type (vector integer) vec))
(format nil "~a~&" (elt vec 0)))
Любой намек? Благодарю вас!
Я попробовал следующий код в sbcl 1.1.14, но кажется, что проверка типа игнорирует объявление векторного элемента.
(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)
Ой! Нет массива, оптимизированного для (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
связана с вектором, который содержит только integer
чисел.
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
Но проверять это во время компиляции? Возможно нет.
(test #(1 2 3))
, я получаю1
, как и ожидалось. И когда я делаю(test '(1 2 3))
, я получаюThe value (1 2 3) is not of type (VECTOR INTEGER).
, как и ожидалось. Я используюsbcl
версии 1.0.57. - person lurker   schedule 11.01.2014(test #(a b c))
не возвращает ошибку, простоA
- person lurker   schedule 11.01.2014