Common Lisp类型与类别区别

时间:2017-03-01 19:52:55

标签: class types common-lisp

Common Lisp class hierarchy的帖子中,Rainer Joswig& Joshua Taylor仔细区分了内置的Common Lisp 类型之间的一些区别,其中类构成了基线的CLOS扩展的一部分。类型/类(加上拖把)的区别也反映在Pfeil的综合hierarchy diagram中。使用该图,似乎可以提取两个不同的层次结构。特别是,我目前最感兴趣的是层次结构的顶层;即,region的直接子类型和子类(因为t既是类型又是类)。以下是从图中提取的一些临时子类型/子类:

对于类型层次结构,t的直接子类型似乎是tatomcharacterrandom-statehash-tablerestartreadtablepackagepathnamestreamfunctionarraysequence和{ {1}}。所有其他类型(如numbercondition)都是其中一种类型的子类型。类型层次结构也不是严格分层的(因为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的子类型。

3 个答案:

答案 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类,内置类或其他类型。

Named types in Common Lisp, using LispWorks

答案 1 :(得分:4)

术语直接子类型几乎没有意义。

为什么您认为charactert直接子类型

但是characteratom的子类型,它是t的子类型!

嗯,也许characteratom直接子类型?

不,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

对于typepsubtypep,事情会更加令人困惑,因为您可以随意生成类型,例如(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箭头来丢弃图表。但事实上,这可能根本不是一个正确的表示,因为listsequence类型的某些对象是cons而其他对象是atom,特别是空的列表是atom

但是,您可以确定整个类层次结构,即使某个类可能有多个超类。

某些实现返回fixnum示例中的class-of类,标准的扩展(fixnum是类型但不是类),以允许{fixnum上的CLOS方法专门化1}}和/或允许优化技巧。

从我尝试的一些实现中,只有CLISP返回了integer类。