我想定义一个描述相同类型事物列表的类型说明符。所以我希望(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
,但是如何?)。此外,解决方案应该可以工作,以便可以在另一个包中创建类型。
答案 0 :(得分:14)
试试这个:
(defun elements-are-of-type (seq type)
(every #'(lambda (x) (typep x type)) seq))
(deftype list-of-type (type)
(let ((predicate (gensym)))
(setf (symbol-function predicate)
#'(lambda (seq) (elements-are-of-type seq type)) )
`(and list (satisfies ,predicate)) ))
(typep '(1 2 3) '(list-of-type integer))
; -> T
(typep '(1 2 a) '(list-of-type integer))
; -> NIL
(typep '(a b c) '(list-of-type symbol))
; -> T
答案 1 :(得分:-1)
我必须承认我不知道普通的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)
扩展为与您发布的代码相当的代码。
此代码定义了当前包中的类型(我想),但将其更改为允许接受包名称应该是微不足道的。