Отличие целого числа от строкового вектора

#common-lisp

Вопрос:

Я пытаюсь определить тип массива. Вот тестовый случай:

 (defun column-summary2 (column)
  (typecase column
    (simple-double-float-vector (format t "Column is a simple-double-float-vector~%"))
    ;; (simple-integer-vector (format t "Column is a simple-integer-vector~%"))
    ;; (simple-string-vector  (format t "Column is a simple-string-vector~%"))
    ((simple-array string (*)) (format t "~A Column is a string-array~%" column))
    ((simple-array float (*)) (format t "~A is a simple-float-array~%" column))
    ((simple-array integer (*)) (format t "~A is a simple-float-array~%" column))
    (bit-vector (make-bit-vector-summary :length (length column) :count (count 1 column))))))
 

Это работает, как и ожидалось , для встроенного типа bit-vector , и с моим собственным simple-double-float-vector типом:

 (deftype simple-double-float-vector (amp;optional (length '*))
  "Simple vector of double-float elements."
  `(simple-array double-float (,length)))
 

но не удается для строки и целого числа:

 LS-USER> (df::column-summary2 #("foo" "bar" "baz"))
#(foo bar baz) Column is a string-array
NIL
LS-USER> (df::column-summary2 #(1 2 3))
#(1 2 3) Column is a string-array
 

Я попытался определить типы для этих двух:

 (deftype simple-integer-vector (amp;optional (length '*))
  "Simple vector of integer elements."
  `(simple-array integer (,length)))

(deftype simple-string-vector (amp;optional (length '*))
  "Simple vector of integer elements."
  `(simple-array string (,length)))
 

Редактировать: Принуждение также, похоже, терпит неудачу:

 CL-USER> (type-of (coerce #(4 4 1 1 2 1 4 2 2 4 4 3 3 3 4 4 4 1 2 1 1 2 2 4 2 1 2 2 4 6 8 2) '(simple-array integer (32))))
(SIMPLE-VECTOR 32)
CL-USER> (type-of (coerce #("foo" "bar" "baz") '(simple-array string (3))))
(SIMPLE-VECTOR 3)
 

но это не помогает. Кажется, что integer и string всегда сливаются. Кто-нибудь может понять, почему?

Комментарии:

1. Интересный. ответ @svante, похоже, предполагает, что принуждение также не решит проблему, и на самом деле это не так, как видно из отредактированного вопроса.

Ответ №1:

typecase можно различать только типы, которые различаются с точки зрения реализации, и очень маловероятно, что массивы integer s и strings являются. Вы можете проверить это, например, с помощью:

 (eq (upgraded-array-element-type 'integer)
    (upgraded-array-element-type 'string))
 

Который, скорее всего, вернется t . И на самом деле вполне вероятно , что upgraded-array-element-type для обоих этих типов это само t по себе : наиболее специализированный массив, в котором может храниться общее string , такой же, как и тот, в котором может храниться общее integer , поскольку оба этих типа действительно требуют, чтобы элементы массива были общими указателями.

Дело в том, что при typecase просмотре массива все, что он может отправлять, — это тип реализации массива, а не что-либо другое, и эти два типа одинаковы во многих случаях, когда они не совпадают концептуально.

Ответ №2:

Типом массива может быть только тот тип , который указан в make-array качестве его :element-type , см. Тип simple-array в спецификации. Если вы используете литералы массива, это, скорее всего, не так.

Он не проверяет во время выполнения тип каждого элемента.

Слово «может» является намеком на то, что на это также влияет обновление типов элементов массива: существует только фиксированный набор (определенная реализация) типов массивов, в основном определяемый наличием специализированного представления. Фактический тип элемента массива является наиболее специализированным из этого набора, который соответствует объявленному типу.

Если вам нужна точная информация во время выполнения, вам нужно обернуть и пометить себя.

Комментарии:

1. Действительно. Похоже, что вы даже не можете создать массив целых чисел в SBCL: (тип (сделать-массив 3 :тип элемента ‘целое число :начальное содержимое #(1 2 3))) => (ПРОСТОЙ-ВЕКТОР 3)

2. Integer является любым целым числом, трудно специализироваться. Попробуй fixnum .

3. Общий Лисп немного забавен тем, что тип «целое число» не имеет четко определенного верхнего предела. В большинстве языков ввод числа 2 в переменную «целочисленной формы», а затем удвоение его 2048 раз, скорее всего, оставит вас с 0, в CL он оставляет вас с 2**2048 (что слишком долго, чтобы вставить в то, что осталось от этого поля для комментариев).