В common-lisp как определяется связь между типами?

#types #lisp #common-lisp

#типы #lisp #common-lisp

Вопрос:

Играя в Lisp, я заметил следующее:

 (subtypep 'string '(array character)) ==> NIL, T
(subtypep '(array character) 'string) ==> NIL, T
  

в то время как

 (typep (make-string x) '(array character)) ==> T
(typep (make-array x :element-type :character) 'string) ==>T
  

для любого значения x.

Это означает, что «subtypep» говорит, что ‘string и’ (символ массива) — это два разных типа, в то время как «typep» говорит, что любой экземпляр одного типа также является экземпляром другого (1)

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

РЕДАКТИРОВАТЬ: как правильно указано (array character) , не обязательно является подтипом string , по простой причине существования многомерных массивов символов. Но я все еще не могу представить экземпляр string , который не имеет типа (array character) .

Ответ №1:

См . http://en.wikipedia.org/wiki/Covariance_and_contravariance_ (computer_science)

Массивы в Common Lisp изменчивы. Вместо того, чтобы пытаться притворяться, что они ковариантны или контравариантны, и добавлять сложные динамические проверки, массивы в CL инвариантны. Таким образом, если они не совпадают, между и нет отношения подтипов (array character 1) (array base-char 1) . Программы не должны хранить неосновные символы в последнем, и программы могут считывать неосновные символы из первого.

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

Ответ №2:

Это проблема реализации:

 ccl e$ rlwrap ./dx86cl64
Loading ~/ccl-init.lisp
Welcome to Clozure Common Lisp Version 1.7-dev-r14614M-trunk  (DarwinX8664)!
? (subtypep 'string '(array character))
T
T
? 
  

Ответ №3:

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

Например, в SBCL, если вы (describe 'string) , вы получите STRING names a primitive type-specifier: (undocumented) . Интересно то, что для base-string его того же, но:

 (subtypep 'base-string 'array) => T
(subtypep 'base-string '(array base-char)) => T
(subtypep 'string 'array) => T
(subtypep 'string '(array character)) => NIL
(subtypep 'string '(array base-char)) => NIL
(subtypep 'string '(array standard-char)) => NIL
(subtypep 'string '(array extended-char)) => NIL
  

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

1. Базовая строка является подтипом (array base-char). Что мешает string быть подтипом (символ массива)?

2. Вероятно, лучшим местом для получения ответа на этот вопрос является список рассылки sbcl-devel . Это может быть оптимизация или ошибка.

Ответ №4:

Попробуйте:

 (subtypep '(vector nil) 'string)
  

в SBCL и других реализациях для понимания. Требование (vector nil) быть подтипом string следует из стандарта, даже если базовый символ и символ эквивалентны в реализации.