在Common Lisp class hierarchy的帖子中,Rainer Joswig& Joshua Taylor仔细区分了内置的Common Lisp 类型和类之间的一些区别,其中类构成了基线的CLOS扩展的一部分。类型/类(加上拖把)的区别也反映在Pfeil的综合hierarchy diagram中。使用该图,似乎可以提取两个不同的层次结构。特别是,我目前最感兴趣的是层次结构的顶层;即,region
的直接子类型和子类(因为t
既是类型又是类)。以下是从图中提取的一些临时子类型/子类:
对于类型层次结构,t
的直接子类型似乎是t
,atom
,character
,random-state
,hash-table
, restart
,readtable
,package
,pathname
,stream
,function
,array
,sequence
和{ {1}}。所有其他类型(如number
或condition
)都是其中一种类型的子类型。类型层次结构也不是严格分层的(因为float
,但这似乎是唯一的例外)。 (ps:类型list
和(subtype t t) => T
未包含在图表中,但也可能是symbol
的直接子类型。)
对于类层次结构,structure-object
的直接子类包括上述所有类型的相应类(t
除外,也许t
现在是{{1}的子类}(?)),再加上atom
。
MOP通过添加类structure-object
(加上一些元子类)来扩展CLOS,但似乎没有添加到standard-object
的直接子类。
有人可以验证这种理解是否正确,还是提供其他说明?
注意:我在上面的类型层次结构描述中发现了至少一个错误。所有列出的子类型(standard-object
等)显然都是metaobject
的子类型,因此它们不是t
的直接子类型。 character
的唯一其他直接子类型似乎是atom
,因为序列可以是t
(非原子)。此外,t
实际上包含在图表中,也是sequence
的子类型。
答案 0 :(得分:6)
在LispWorks中绘制T的CL子类型:
查找子类型:
(defun find-synonym-types (type1 types)
(remove-if-not (lambda (type2)
(and (not (eq type1 type2))
(subtypep type1 type2)
(subtypep type2 type1)))
types))
(defun find-all-types-in-packages (packages &key include-nil)
(let ((types nil))
(loop for package in packages
when (find-package package)
do (do-external-symbols (sym (find-package package))
(when (ignore-errors (subtypep sym t))
(let ((synonyms (find-synonym-types sym types)))
(if synonyms
(pushnew sym (get (first synonyms) :type-synonyms))
(pushnew sym types))))))
(if include-nil types (remove nil types))))
(defun direct-subtypes (supertype &key all-types)
(loop with subtypes = (remove supertype (loop for type in all-types
when (subtypep type supertype)
collect type))
for type in subtypes
when (loop for type2 in (remove type subtypes)
never (subtypep type type2))
collect type))
绘制图形:
#+capi
(defun class-color (class-name)
(typecase (find-class class-name)
(standard-class :blue)
(built-in-class :violet)
(structure-class :brown)
(otherwise :red)))
#capi
(defun graph-subtypes-from-t ()
(let ((all-types (find-all-types-in-packages '("CL" "CLOS"))))
(capi:contain
(make-instance
'capi:graph-pane
:roots '(t)
:children-function (lambda (type)
(direct-subtypes type :all-types all-types))
:node-pane-function #'(lambda (graph-pane node)
(declare (ignore graph-pane))
(make-instance
'capi:item-pinboard-object
:text (format
nil "~{~a~^, ~}"
(cons node
(get node :type-synonyms)))
:graphics-args `(:foreground
,(if (find-class node
nil)
(class-color node)
:black))))
:edge-pane-function #'(lambda (self from to)
(declare (ignore self from to))
(make-instance
'capi:arrow-pinboard-object
:graphics-args '(:foreground
:grey))))
:title "Common Lisp Subtypes in LispWorks")))
<强>图形强>
具有相应CLOS类的类型用蓝色写,结构类用棕色。未绘制类型NIL
。包括CLOS MOP中的类型/类。某些类型有多个名称。另请注意,此图特定于LispWorks,尤其是哪些类型实际上也是结构,CLOS类,内置类或其他类型。
答案 1 :(得分:4)
术语直接子类型几乎没有意义。
为什么您认为character
是t
的直接子类型?
但是character
是atom
的子类型,它是t
的子类型!
嗯,也许character
是atom
的直接子类型?
不,character
是(or character number)
的子类型,是atom
的子类型。
那么,也许character
是(or character number)
的直接子类型?
不,character
是(or character integer)
的子类型,是(or character number)
的子类型。
您可以将类视为整数,将类型视为有理数 - 在3和4之间没有整数,但在任何两种不同的有理数之间存在大量的有理数。
答案 2 :(得分:1)
你已经知道Common Lisp中有类型和类。
类型分类对象,而类标记对象。此外,对象可以是多种类型,但它是单个类的直接实例。
如果您通过type-of
向对象询问其类型,则可能会获得许多有效答案。一个非详尽的例子:
(type-of 1)
=> (integer 1 1)
OR => bit
OR => (unsigned-byte 1)
OR => (mod 2)
OR => (integer (0) (2))
OR => (signed-byte 1)
OR => (signed-byte 16)
OR => fixnum
OR => integer
OR => (integer * *)
OR => rational
OR => real
OR => number
OR => t
OR => atom
对于typep
和subtypep
,事情会更加令人困惑,因为您可以随意生成类型,例如(eql 1)
,(member 1)
,(or fixnum bignum)
, (and (integer * 1) (integer 1 *))
,(not (satisfies zerop))
,(satisfies oddp)
等,以获得真实的结果,同样也是错误的结果。
但是,对于每个对象,您只有一个类:
(class-of 1)
=> #<BUILT-IN-CLASS INTEGER>
实际上,您无法确定整个类型层次结构。有一种观点认为任何东西都是t
,没有什么是nil
,并且可能存在原子标准类型的层次结构。但实际情况是存在复合类型和用户定义的类型,因此在技术上不可能绘制完整的类型层次结构,因为需要为每个可以想象的对象查看subtypep
的结果。
即便如此,类型之间可能不存在层次结构。如果您发现了错误,我相信作者不希望使用除atom
以外的每种类型的cons
箭头来丢弃图表。但事实上,这可能根本不是一个正确的表示,因为list
和sequence
类型的某些对象是cons
而其他对象是atom
,特别是空的列表是atom
。
但是,您可以确定整个类层次结构,即使某个类可能有多个超类。
某些实现返回fixnum
示例中的class-of
类,标准的扩展(fixnum
是类型但不是类),以允许{fixnum
上的CLOS方法专门化1}}和/或允许优化技巧。
从我尝试的一些实现中,只有CLISP返回了integer
类。