2017-04-22 60 views
3

我对SBCL的适用性最感兴趣,但也对Common Lisp的其他实现感到好奇。我们的type hierarchy在常见的lisp中,返回两个对象最具体的超类型的函数是什么?

我想要一个函数,给定两个对象作为参数,返回符号表示适用于这两个对象的最具体的超类型。它的使用看起来是这样的:

(most-specific-super-type x y) 

因此,举例来说,短浮子和长期浮动的两个子类型的超类型float的。

如果比较长浮点数和整数,最具体的超级类型是real

如果比较一个复数和一个浮点数,最具体的超级类型是number

比较该类型层次结构中单独树中的两个对象,如果对象不是cons,我们可能会返回类型T或可能​​。

我很想避免自己写这个,我的直觉告诉我,它看起来像已经写好的那种功能。

我主要对标准语言中已定义的类型感兴趣,但是我的直觉也告诉我必须有一个与CLOS类相关的函数,以确定类的优先级。

所以,如果有,这将是适用于类和类型两者共同的功能,这将是超好,但我会很高兴,如果有只是类型的解决方案......

+0

我不知道一个准备的使用f但是在https://www.informatimago.com/articles/cl-types/找到了图表(和源代码)很有帮助。 –

+0

不要写'原子。引号运算符不是符号或名称的一部分。 –

+0

@RainerJoswig:谢谢Rainer,不确定在文本问题的上下文中将符号的格式设置为不同于文本/字符串的最佳方式:) – DJMelksham

回答

1

当我想到这对其他人来说是值得的,而且我在经过大量搜索之后,无法在任何地方找到这样的解决方案,而且我没有得到太多的叮咬,我一直在鞭打基本未被优化的逻辑自己解决方案。

这不是一个最终的工作版本,但应该让任何其他人寻找相同的问题解决方案,在这一点上,他们可以硬化和重构。请评论并提供任何更正/修复/问题。

感谢@Martin Buchmann发布https://www.informatimago.com/articles/cl-types/,这是我开始使用的。

第1步:设置散列表。

(defvar *type-hash* (make-hash-table)) 

步骤2:定义有效的类型谓词的功能。在SBCL上,*对于有效的类型说明符返回TRUE ...因此,我们只是排除该特定的情况并使用处理程序案例来停止程序在非有效的类型指示符上引发条件。

(defun valid-type-p (type-designator) 
    (handler-case (and (SB-EXT:VALID-TYPE-SPECIFIER-P type-designator) 
        (not (eq type-designator 'cl:*))))) 

步骤3:我们提取从:cl包,这是说,口齿不清语言基本上共同的外部符号。我们使用我们的valid-type-p谓词来测试每个符号。如果其有效,我们将其推送到我们的集合types

注意::cl不是唯一可以做到这一点的软件包。如果你在你自己的创作包中使用外部cl符号,并且定义了一些你自己导出的自定义CLOS类,我想这也会捕获其中包含的类层次结构。我没有太多测试,所以玩了一下。在我的例子中,我避免了这一点,因为我相信CLOS层次结构和类可以在运行时更改,这可能会导致层次结构无效,除非每次都重新计算它,而我相当确信内部类型是对我而言目前最有用的那些,并且不会改变。

使用每个有效类型作为键,并使用嵌套循环,在此操作之后,散列中的每个键现在会给我们一个关键字是有效子类型的类型列表。

(let ((types nil)) 
    (do-external-symbols (s :cl) 
    (when (ignore-errors (valid-type-p s)) 
     (push s types))) 

    (loop for type1 in types 
    do (loop for type2 in types 
      do (if (subtypep type1 type2) 
        (push type2 (gethash type1 *type-hash*)))))) 

第4步:我们定义一个函数来给我们最具体的超强型两种类型。这是如何运作的?

首先,我们得到使用我们新填充的散列获得的超类型的intersection

其次,我们使用subtypep作为排序谓词对路口进行排序。对我来说,使用subtypep当然不是一个直观的排序谓词,直到我意识到使用它来排序层次结构是有意义的。我仍然不是100%肯定有没有一些边缘情况,但:\

无论如何,我们将返回一个列表的低排名类型的超类型在第一个位置,并得到它,我们干脆把car

(defun supertype-of-types (type1 type2) 
    (car 
    (sort 
    (intersection (gethash type1 *type-hash*) 
        (gethash type2 *type-hash*)) 
    #'subtypep))) 

步骤5:超型的类型已经是一个有用的功能,但最终我们要在实际值,而不是仅仅代表类型手动输入符号使用。

功能type-of似乎在SBCL中返回相对特定类型的值,但实际上它可以返回列表。因此,我们需要编写一个快速的函数提取表示从列表中的第一部分类型的符号,如果这种情况发生......

(defun type-of-object (x) 
    (let ((type (type-of x))) 
    (if (listp type) 
     (car type) 
     type))) 

步骤6:最后,我们写所需的功能。我们首先明确检查两个对象中的一个是否是另一个对象类型的子类型。如果是,那是最具体的超类型。我们这样做的部分原因是SBCL返回的对象类型比typeof询问对象时仅由类型符号表示的类型更具体。对于我的优化目的,如果可能的话,我希望能够使用这些更具体的类型规范,并且这是一个快速的混合,在我明确地找出扩展类型说明符之前获取其中的一些。如果我没有放入,我们的下一个技巧返回'INTEGER作为459和-345最具体的超类型,因为SBCL返回(INTEGER 0 4611686018427387903)的类型为459和fixnum,类型为-345,类型将返回为INTEGER,而它们实际上都是特定类型fixnum。无论如何,如果一个值的类型不是另一个值类型的子类型,我们使用我们在步骤5中创建的super-type-of-types函数,并且我们总是可以返回T作为最差情况,因为所有东西都是子类型型T.

(defun most-specialised-supertype (x y) 
    (let ((typex (type-of x)) 
     (typey (type-of y))) 
    (cond ((subtypep typex typey) typey) 
      ((subtypep typey typex) typex) 
      ((supertype-of-types (type-of-object x) (type-of-object y))) 
      (t t)))) 

和它进行一些测试纺:

(most-specialised-supertype 5.0l0 435789) 
REAL 

(most-specialised-supertype 1.0s0 1.0l0) 
FLOAT 

(most-specialised-supertype 1.0 #c(1 1)) 
NUMBER 

(most-specialised-supertype 'symbol "string") 
ATOM 

(most-specialised-supertype #(1 2 3) #*101) 
VECTOR 

我相信它至少看起来它有点工作:)

相关问题