2.5 Массивы

Массив (array) является объектом с элементами расположенными в соответствие с декартовой системой координат.

Количество измерений массива называется ранг (это терминология взята из APL). Ранг является неотрицательных целым. Также каждое измерение само по себе является неотрицательным целым. Общее количество элементов в массиве является произведением размеров всех измерений.

Реализация Common Lisp’а может налагать ограничение на ранг массива, но данное ограничение не может быть менее 7. Таким образом, любая Common Lisp программа может использовать массивы с семью и менее измерениями. (Программа может получить текущее ограничение для ранга для используемой системы с помощью константы array-rank-limit.)

Допускается существование нулевого ранга. В этом случае, массив не содержит элементов, и любой доступ к элементам является ошибкой. При этом другие свойства массива использоваться могут. Если ранг равен нулю, тогда массив не имеет измерений, и их произведение приравнивается к 1 (FIXME). Таким образом массив с нулевым рангом содержит один элемент.

Элемент массива задаётся последовательностью индексов. Длина данной последовательности должна равняется рангу массива. Каждый индекс должен быть неотрицательным целым строго меньшим размеру соответствующего измерения. Также индексация массива начинается с нуля, а не с единицы, как в по умолчанию Fortran’е.

В качестве примера, предположим, что переменная foo обозначает двумерный массив с размерами измерений 3 и 5. Первый индекс может быть 0, 1 или 2, и второй индекс может быть 0, 1, 2, 3 или 4. Обращение к элементам массива может быть осуществлено с помощью функции aref, например, (aref foo 2 1) ссылается на элемент массива (2, 1). Следует отметить, что aref принимает переменное число аргументов: массив, и столько индексов, сколько измерений у массива. Массив с нулевым рангом не имеет измерений, и в таком случае aref принимает только один параметр – массив, и не принимает индексы, и возвращает одиночный элемент массива.

В целом, массивы могут быть многомерными, могут иметь общее содержимое с другими массивами. и могут динамически менять свой размер после создания (и увеличивать, и уменьшать). Одномерный массив может также иметь указатель заполнения.

Многомерные массивы хранят элементы построчно. Это значит, что внутренне многомерный массив хранится как одномерный массив с порядком элементов, соответствующим лексикографическому порядку их индексов. Это важно в двух ситуациях: (1) когда массивы с разными измерениями имеют общее содержимое, и (2) когда осуществляется доступ к очень большому массиву в виртуальной памяти. (Первая ситуация касается семантики; вторая — эффективности)

Массив, что не указывает на другой массив, не имеет указателя заполнения и не имеет динамически расширяемого размера после создания называется простым массивом. Пользователи могут декларировать то, что конкретный массив будет простым. Некоторые реализации могут обрабатывать простые массивы более эффективным способом, например, простые массивы могут храниться более компактно, чем непростые.

Когда вызывается make-array, если один или более из :adjustable, :fill-pointer и :displaced-to аргументов равен истине, тогда является ли результат простым массивом не определено. Однако если все три аргумента равны лжи, тогда результат гарантированно будет простым массивом.

2.5.1 Векторы

В Common Lisp’е одномерные массивы называется векторами, и составляют тип vector (который в свою очередь является подтипом array). Вектора и списки вместе являются последовательностями. Они отличаются тем, что любой элемент одномерного массива может быть получен за константное время, тогда как среднее время доступа к компоненту для списка линейно зависит от длины списка, с другой стороны, добавление нового элемента в начала списка занимает константное время, тогда как эта же операция для массива занимает время линейно зависящее от длины массива.

Обычный вектор (одномерный массив, который может содержать любой тип объектов, но не имеющий дополнительных атрибутов) может быть записан с помощью перечисления элементов разделённых пробелом и окружённых #( и ). Например:

#(a b c)                    ;Вектор из трёх элементов
#()                         ;Пустой вектор
#(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)
                            ;Вектор содержит простые числа меньшие пятидесяти

Следует отметить, что когда функция read парсит данный синтаксис, она всегда создаёт простой массив. __________________________________________

Обоснование: Многие люди рекомендовали использовать квадратные скобки для задания векторов так: [a b c] вместо #(a b c). Данная запись короче, возможно более читаема, и безусловно совпадает с культурными традициями в других областях компьютерных наук и математики. Однако, для достижения предельной полезности от пользовательских макросимволов, что расширяют возможности функции read, необходимо было оставить некоторые строковые символы для этих пользовательских целей. Опыт использования MacLisp’а показывает, что пользователи, особенно разработчики языков для использования в исследованиях искусственного интеллекта, часто хотят определять специальные значения для квадратных скобок. Таким образом Common Lisp не использует квадратных и фигурных скобок в своём синтаксисе.

___________________________________________________________________________________________________________

Реализации могут содержать специализированные представления массивов для достижения эффективности в случаях, когда все элементы принадлежат одному определённому типу (например, числовому). Все реализации содержат специальные массивы в случаях, когда все элементы являются строковыми символами (или специализированное подмножество строковых символов). Такие одномерные массивы называются строки. Все реализации также должны содержать специализированные битовые массивы, которые принадлежат типу (array bit). Такие одномерные массивы называются битовые векторы.

2.5.2 Строки

base-string  (vector base-char)
simple-base-string  (simple-array base-char (*))

Реализация может поддерживать другие типы строк. Все функции Common Lisp’а взаимодействуют со строками одинаково. Однако следует отметить, вставка extended character в base string является ошибкой.

Строковый (string) тип является подтипом векторного (vector) типа.

Строка может быть записана как последовательность символов, с предшествующим и последующим символом двойной кавычки ". Любой символ " или \ в данной последовательности должен иметь предшествующий символ \.

Например:

"Foo"                         ;Строка из трёх символов
""                            ;Пустая строка
"\"APL\\360?\" he cried."     ;Строка из двенадцати символов
"|x| = |-x|"                  ;Строка из десяти символов

Необходимо отметить, что символ вертикальной черты | в строке не должен быть экранирован с помощью \. Также как и любая двойная кавычка в имени символа, записанного с использованием вертикальных черт, не нуждается в экранировании. Записи с помощью двойной кавычки и вертикальной черты похожи, но используются для разных целей: двойная кавычка указывает на строку, содержащую строковые символы, тогда как вертикальная черта указывает на символ, имя которого содержит последовательность строковых символов.

Строковые символы обрамленные двойными кавычками, считываются слева направо. Индекс символа больше индекса предыдущего символа на 1. Самый левый символ строки имеет индекс 0, следующий 1, следующий 2, и т.д.

Следует отметить, что функция prin1 будет выводить на печать в данном синтаксисе любой вектор строковых символов (не только простой), но функция read при разборе данного синтаксиса будет всегда создавать простую строку.

2.5.3 Битовые векторы

Битовый вектор может быть записан в виде последовательности битов заключённых в строку с предшествующей #*; любой разделитель, например, как пробел завершает синтаксис битового вектора. Например:

#*10110     ;Пятибитный битовый вектор; нулевой бит 1
#*          ;Пустой битовый вектор

Биты записанные после #*, читаются слева направо. Индекс каждого бита больше индекса предыдущего бита на 1. Индекс самого левого бита 0, следующего 1 и т.д.

Функция prin1 выводит любой битовый вектор (не только простой) в этом синтаксисе, однако функция read при разборе этого синтаксиса будет всегда создавать простой битовый вектор.