Обратите внимание, что принятие деклараций в качестве проверок типов - это ничего, что предусмотрено стандартным 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
номера.
CL-USER 21 > (typep '#(a "b" #\c) '(vector integer))
T
Вышеприведенные возвращает истина в моем Лиспе, потому что вектор является общим вектором и он может хранить целые числа. Таким образом, он проверяет тип вектора, но ему все равно, является ли содержимое вектора фактически целочисленным типом. Он просто говорит, что вектор COULD содержит целые числа.
Предикатные на основе проверки типа
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))' I get 'Значение (1 2 3) не имеет типа (VECTOR INTEGER).' Как ожидалось. Я использую 'sbcl' версии 1.0.57. – lurker
@mrbatch try (test # ('1 2 3)) возвращает' 1 без предупреждения/ошибки для меня (SBCL 1.1.14) – verdammelt
@verdammelt ах да, я вижу. Также '(test # (a b c))' не возвращает ошибку, просто 'A' – lurker