在常见的Lisp中,什么是返回两个对象的最特定超类型的函数?

DJ梅尔舍姆

我对SBCL的适用性最感兴趣,但对Common Lisp的其他实现也很好奇。

在Common Lisp中,我们具有类型层次结构

我想要一个给定两个对象作为参数的函数,该函数返回表示适用于这两个对象的最特定超级类型的符号。它的用法类似于:

(most-specific-super-type x y)

因此,例如,短浮点型和长浮点型都是super-type的子类型float

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

如果将复数和浮点数进行比较,则最具体的超类型为number

比较该类型层次结构中来自不同树的两个对象,大概会返回该类型,T或者atom在对象不是a的情况下返回cons

我很想避免自己写这个,我的直觉告诉我,好像已经编写了那种函数。

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

因此,如果有一个同时适用于类和类型的函数,那将是超级,但如果仅针对类型有解决方案,我将很高兴...

DJ梅尔舍姆

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

这不是最终的工作版本,但是应该使其他任何人寻求相同的问题来解决,然后他们可以进行强化和重构。请发表评论并提供任何更正/修正/问题。

感谢@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包装中提取外部符号,也就是说,基本上是通用的lisp语言。我们使用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返回459和-450(INTEGER 0 4611686018427387903)的类型。fixnum对于-345类型,最常见的超级类型将作为返回INTEGER,而它们实际上都是特定类型fixnum

无论如何,如果一个值的类型不是另一个值的类型的子类型,我们将使用super-type-of-types在步骤5中创建函数,并且在最坏的情况下我们总是可以返回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

我相信它至少看起来像是在起作用:)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

两个类型集/元组中的常见类型

如何从两个不同对象列表中获取不常见对象

比较两个对象引用的常见情况

Elixir从两个列表中删除常见元素

Haskell中两个函数的最通用的“乘积”类型

如何在Ruby中的两个单独的字符串之间返回不常见的字符?

从两个序列中过滤出常见条目,返回两个列表,其中包含原始列表中的唯一条目

从两个表中检索 MySQL 结果,不包括特定列中两个表中常见的内容

在Lisp中返回两个集合的并集(按字母顺序)的函数

如何从 R 中的两个 df 获取常见(反之亦然)和不常见的行

比较两个excel文件并返回不常见的行

如何使用作为返回类型最专业型两个对象的?

是否可以声明一个函数,该函数接受超类实例的数组并返回最特定的子类类型

在C ++函数中返回两种不同类型的两个值

异步函数不允许打字稿中两个诺言类型的返回类型

从列表中的两个不同对象返回LINQ select查询中的特定对象

如何比较两个文件中数组的每个对象中常见的一个字段并更新数组

PowerShell 5.1 为什么这两个函数返回不同的类型

尝试基于两个常见列合并R中的多个tsv文件

如何在SQL的两个表中获取具有不常见值的行?

如何识别两个熊猫数据框中的常见元素

Google可视化中两个图表的常见图例

Linq 查询仅选择两个列表中的常见项目

从两个列表中获取不常见的元素-KOTLIN

Power BI Desktop 中两个事实和常见维度表之间的交叉筛选

删除两个文件中不常见的行,但保持文件结构

查找两个文件之间的常见模式

如何忽略两个表中常见的字段

比较两个文件并删除常见行