как указать тип элемента в векторе sbcl (или common lisp)?

Я попробовал следующий код в sbcl 1.1.14, но кажется, что проверка типа игнорирует объявление векторного элемента.

(defun test (vec)
  (declare (type (vector integer) vec))
  (format nil "~a~&" (elt vec 0)))

Любой намек? Благодарю вас!


person user3185284    schedule 11.01.2014    source источник
comment
Не могли бы вы уточнить, что вы имеете в виду под проверкой типа игнорирует объявление? Когда я запускаю ваш код и делаю (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
comment
@mrbatch try (test #('1 2 3)) возвращает '1 без предупреждения/ошибки для меня (SBCL 1.1.14)   -  person verdammelt    schedule 11.01.2014
comment
@verdammelt ах да, понятно. Также (test #(a b c)) не возвращает ошибку, просто A   -  person lurker    schedule 11.01.2014


Ответы (1)


Прежде всего обратите внимание, что использование объявлений в качестве проверок типов не предусмотрено стандартным 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

Но проверять это во время компиляции? Возможно нет.

person Rainer Joswig    schedule 11.01.2014
comment
Большое спасибо! Очень понятное и информативное объяснение. Теперь я знаю больше о массиве. Это действительно не просто. Такой дизайн интересен, хотя обычно требуется массив (вектор) элементов одного специализированного типа, по крайней мере, для научных вычислений. Надеюсь, что common lisp может предоставить массив, специализированный для любого типа. - person user3185284; 12.01.2014
comment
@ user3185284: Как это нужно? Какой науке это нужно? Обратите внимание, что type может быть чем-то вроде всех простых чисел или всех красных автомобилей, по крайней мере, с 4 дверями. Возможно, вы имеете в виду классы? - person Svante; 15.01.2014