Я хотел бы определить спецификатор типа, который описывает список вещей того же типа. Таким образом, я хотел бы иметь (list-of integer)
подобный (array integer)
(который встроен). Я могу создать его для определенного типа, как это:
(defun elements-are-integer (seq)
(every #'(lambda (x) (typep x 'integer)) seq))
(deftype list-of-integer ()
'(and list (satisfies elements-are-integer)))
Однако это означает, что я должен сделать это для каждого возможного типа. Как я могу изменить этот код так, чтобы тип взял бы другой тип в качестве аргумента и создал бы satisfies
утвердить на лету? Проблема состоит в том что satisfies
требует глобального символа, и я не знаю, как определить функцию предиката в надлежащем контексте (я предполагаю, что я должен gensym
это так или иначе, но как?). Кроме того, решение должно работать так, чтобы тип мог быть создан в другом пакете.
Должен признаться, я не настолько хорошо знаю common lisp, чтобы понять, для чего именно используется deftype, но этот макрос должен это сделать...
(defmacro deftype-list-of (type)
(let* ((etfname (intern (concatenate 'string "ELEMENTS-ARE-"
(symbol-name type))))
(ltname (intern (concatenate 'string "LIST-OF-"
(symbol-name type))))
(tcdef `(defun ,etfname (seq)
(every (lambda (x) (typep x ',type)) seq)))
(ltdef `(deftype ,ltname ()
'(and list (satisfies ,etfname)))))
(if (fboundp etfname)
ltdef
`(progn ,tcdef ,ltdef))))
Например, (deftype-list-of integer)
расширяется до кода, эквивалентного тому, который вы разместили.
Этот код определяет тип в текущем пакете (я полагаю), но изменение его для возможности принимать имя пакета должно быть тривиальным.