在Common Lisp中,如何定义通用数据类型说明符(如整数列表)?

时间:2010-07-09 06:00:29

标签: common-lisp

我想定义一个描述相同类型事物列表的类型说明符。所以我希望(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,但是如何?)。此外,解决方案应该可以工作,以便可以在另一个包中创建类型。

2 个答案:

答案 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)扩展为与您发布的代码相当的代码。

此代码定义了当前包中的类型(我想),但将其更改为允许接受包名称应该是微不足道的。