#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 следует из стандарта, даже если базовый символ и символ эквивалентны в реализации.