← Архив: Common Lisp

Определение типа.

Author: · 24.02.2011 12:20
· original author: Paul.Alkhimov
Я никак не могу понять и запомнить правила, по которому задаются типы элементов массивов, структур и классов.
Я пока столкнулся с необходимостью задания типов в определениях классов, структур, при создании массивов, при декларировании типов параметров функции.
В некоторых случаях тип пишется просто, в некоторых - через QUOTE. Кто-то может пояснить, почему?
И, главное, какое общее правило для употребления типов?
Мой случай такой: у меня есть массив из трёх флоатов (в моём случае я сделал тип coordinate).
Как будет выглядеть тип элемента структуры, где элемент - это массив из трёх флоатов?
Но всё-же общее правило интереснее.
P.S. Когда я сделал структуру и создал массив структур, то элемент массива определился (type-of) как BIT. Почему?
· original author: Paul.Alkhimov
При этом, когда я подсунул :initial-element, всё получилось как надо...
· original author: allchemist
В некоторых случаях тип пишется просто, в некоторых - через QUOTE. Кто-то может пояснить, почему?
> И, главное, какое общее правило для употребления типов?
Там, где тип должен быть известен заранее, т.е. на этапе компиляци, использовать quote не нужно. Пример - декларации типов.
Там, где тип передается как аргумент в рантайме, он должен цитироваться. Пример - параметр element-type в make-array. Функции может быть передан любой тип, а также переменная, содержащая его. Поэтому значение должно цитироваться, т.к. если передать в make-array символ single-float, система будет пытаться получить значение переменной single-float.


P.S. Когда я сделал структуру и создал массив структур, то элемент массива определился (type-of) как BIT. Почему?
Чтобы стало понятно, попробуй вычислить (type-of 1) или (type-of 0). :)
· original author: slav
Замечание не совсем в тему вопроса, но, думаю, будет полезно:
> P.S. Когда я сделал структуру и создал массив структур...
При этом тип элемента массива у тебя будет t. Причина в том, что если ты записываешь в элемент массива что-то, то этот элемент массива после этого должен стать eq с тем значением, которое ты туда записал. Т. е. чтобы делать массивы из структур, нужно либо определять оператор eq для структур как поэлементное сравнение (и присваивание как поэлементное копирование), либо не допускать unboxed структур. Второй вариант более прост и эффективен.
А узнать во что превратится твой тип, указанный в :element-type у make-array, можно с помощью функции upgraded-array-element-type.
· original author: Paul.Alkhimov
Спасибо за ответы.
@slav: где-то можно об этом поподробнее?
Или хотя-бы, почему оставлять boxed проще и эффективнее? Это же, как я понимаю, как минимум одна косвенная ссылка в памяти. Т.е. на ровном месте появляются накладные расходы.
Я ведь массив использую не потому, что мне так удобнее, а потому, что он обладает определёнными свойствами. В моём случае, это скорость произвольного доступа по индексу. И тут добавляется эта косвенная адресация...
· original author: allchemist
boxed-массив - массив указателей на произвольные объекты. unboxed - массив чисел одинакового типа. Реальную скорость можно получить лишь используя unboxed-массивы с соответствующими оптимизациями и декларациями. Если гибкость важнее скорости, можно использовать boxed-массив. unboxed (специализированные) массивы могут содержать элементы ограниченного набора типов. Узнать,поддерживается ли специализация массива по какому-то типу можно с помощью upgraded-array-element-type. 
· original author: slav
> @slav: где-то можно об этом поподробнее?
Честно говоря не знаю точно где про это посмотреть - мне этот вопрос кто-то здесь разъяснил, в CLHS этого не нашёл (кроме описания upgraded-array-element-type и того что с ним).
Суть в том, что если мы записываем какое-то значение в массив (равно как и в слот структуры или класса, или в одну из ячеек cons-а), то последующий тест eq этого элемента массива с тем, что мы туда записывали, должен давать t. Таким образом, если массив (или слот структуры) типизирован чем-то, отличным от t, то мы обязаны сравнение объектов этого типа по eq выполнять как поэлементное сравнение (а не как просто сравнение указателей на них) - как сделано в sbcl для чисел к примеру. Т. е. это потребует считать идентичными любые 2 структуры, имеющие одинаковые значения слотов. Что, насколько я понимаю, не соотвествует стандарту, ибо (eq (make-struct) (make-struct)) должно быть nil.
Если очень нужно массив из упакованных в него структур - такое можно разместить в foreign-памяти.