2014-01-11 2 views
3

Я пробовал следующий код в sbcl 1.1.14, но, похоже, проверка типа игнорирует объявление для векторного элемента.Как указать тип элемента в векторе sbcl (или общий lisp)?

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

Подсказка? Спасибо!

+0

Можете ли вы уточнить, что вы имеете в виду, что * проверка типа игнорирует объявление *? Когда я запускаю ваш код и делаю '(test # (1 2 3))' Я получаю '1', как и ожидалось. И когда я делаю '(test '(1 2 3))' I get 'Значение (1 2 3) не имеет типа (VECTOR INTEGER).' Как ожидалось. Я использую 'sbcl' версии 1.0.57. – lurker

+0

@mrbatch try (test # ('1 2 3)) возвращает' 1 без предупреждения/ошибки для меня (SBCL 1.1.14) – verdammelt

+0

@verdammelt ах да, я вижу. Также '(test # (a b c))' не возвращает ошибку, просто 'A' – lurker

ответ

10

Обратите внимание, что принятие деклараций в качестве проверок типов - это ничего, что предусмотрено стандартным 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 

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

+0

Большое вам спасибо! Очень четкое и информативное объяснение. Теперь я знаю больше массива. Это действительно не просто. Такой дизайн интересен, хотя обычно требуется массив (вектор) элементов с одним специализированным типом, по крайней мере для научных вычислений. Hope common lisp может предоставить массив, специализированный для любого типа. – user3185284

+0

@ user3185284: Как это необходимо? Какая наука нуждается в этом? Обратите внимание, что _type_ может быть чем-то вроде «всех простых чисел» или «всех красных автомобилей с не менее чем четырьмя дверями». Возможно, вы думаете о _classes_? – Svante