在Common Lisp中更改方法分派

查尔斯·朗格卢瓦

我正在尝试使用Common Lisp的CLOS模拟类似于Haskell的类型类的东西。也就是说,我希望能够在对象的“类型类”而不是其超类上分派一个方法。

我为具有并实现typeclasss(只是其他类)的类定义了一个元类。这些类(实现类型类的那些类)具有一个插槽,其中包含它们实现的类型类的列表。
我希望能够为类型类定义方法,然后能够在其类实现该类型类的对象上分派该方法。而且我希望能够动态添加和删除类型类。

我认为我可以通过更改方法分派算法来做到这一点,尽管这似乎不太简单。

任何人都对CLOS和MOP感到满意,可以给我一些建议吗?

谢谢。

编辑:我的问题可能被指定为,如何实现compute-applicable-methods-using-classescompute-applicable-methods“自定义”泛型函数类,以便如果泛型函数方法的某些专门化子是typeclasses(其元类为'typeclass'类的类),则相应参数的类必须实现typeclass(这仅意味着将typeclass存储在参数的类的插槽中)才能适用该方法?
根据我从文档中了解到的信息,compute-discriminating-function第一次调用泛型函数时,该函数将首先尝试通过来获取适用的方法compute-applicable-methods-using-classes,如果不成功,将尝试与进行相同的操作compute-applicable-methods
虽然我的定义compute-applicable-methods-using-classes似乎正常,通用函数无法分派适用的函数。因此,问题一定在compute-discriminating-function或中compute-effective-method

参见代码

加速剂

这在Common Lisp中不容易实现。

在Common Lisp中,操作(泛型函数)与类型(类)是分开的,即它们不是由类型“拥有”的。它们的分发是在运行时完成的,还可以在运行时添加,修改和删除方法。

通常,缺少方法的错误仅在运行时发出信号。编译器无法知道通用函数是否被“正确”使用。

Common Lisp中的惯用方式是使用泛型函数并描述其需求,换句话说,Common Lisp中最接近接口的是一组泛型函数和一个标记mixin类。但最通常的是,仅指定一个协议,并且它依赖于其他协议。参见例如CLIM规范

对于类型类,它是一项关键功能,不仅使语言保持完全类型安全,而且在该方面也具有很高的可扩展性。否则,至少从编译器的角度来看,要么类型系统太严格,要么缺乏表达能力会导致类型不安全的情况。请注意,Haskell在运行时不保留或不必保留对象类型,它在编译时进行每种类型推断,这与惯用的Common Lisp相反。

要在运行时拥有类似于Common Lisp中的类型类的内容,您有几种选择

如果您选择使用其规则支持类型类,建议您使用元对象协议

  • 定义一个新的通用函数元类(即从继承的元类standard-generic-function

  • 专门compute-applicable-methods-using-classes返回false作为第二个值,因为Common Lisp中的类仅由它们的名称表示,它们不是“可参数化的”或“可约束的”

  • 专门compute-applicable-methods检查参数的元类的类型或规则,进行相应调度并可能记录结果

如果您只选择可参数化的类型(例如,模板,泛型),则现有的选项是Lisp接口库,您可以在其中传递使用协议实现特定策略的对象。但是,我主要将其视为策略模式的实现控制的显式倒置,而不是实际的可参数化类型。

对于实际的可参数化类型,您可以定义抽象的未参数化类,从中可以用有趣的名称来插入具体实例,例如lib1:collection<lib2:object>,其中collection是在lib1包中定义的抽象类,而lib2:object实际上是名称的一部分,就像具体类一样。

最后一种方法的好处是您可以在CLOS中的任何位置使用这些类和名称。

主要缺点是您仍然必须生成具体的类,因此您可能会有自己的defmethod-like宏,该宏会扩展为使用find-class-like函数的代码,该函数知道如何执行此操作。这样就破坏了我刚才提到的好处的很大一部分,否则您应该遵循在自己的库中定义每个具体类的原则,然后再将它们用作专门化器。

另一个缺点是,如果没有进一步的非常规管道,这将是静态的,不是真正的通用类,因为它没有考虑到例如lib1:collection<lib2:subobject>可能是的子类,lib1:collection<lib2:object>反之亦然。通常,它没有考虑计算机科学中所谓的协方差和逆方差

但是您可以实现它:lib:collection<in out>可以用一个自变量和一个协变量表示抽象类。如果可能的话,最困难的部分是生成和维护具体类之间的关系。

通常,在Lisp实施级别上,编译时方法会更合适。这样的Lisp很可能不是Common Lisp。您可以做的一件事是为Haskell使用类似Lisp的语法。完整的元循环将是使其在宏扩展级别上完全类型安全,例如,为宏本身而不是仅针对其生成的代码生成编译时类型错误。


编辑:编辑完您的问题后,我必须说,只要方法中存在类型类专门化器compute-applicable-methods-using-classes 就必须nil作为第二个值返回您也可以call-next-method

这与适用方法中的类型类专门化器不同请记住,CLOS对类型类一无所知,因此通过返回c-a-m-u-c带有真正第二个值的值,就意味着仅给定类就可以记忆(缓存)。

您必须真正专心compute-applicable-methods于正确的类型类分派。如果有机会进行记忆(缓存),则必须在此处自己进行。

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

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

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

更改-在Common Lisp中变为+

来自分类Dev

更改-在Common Lisp中变为+

来自分类Dev

在Common Lisp REPL中更改文本的颜色

来自分类Dev

在Common Lisp(CLOS)中列出对象方法

来自分类Dev

(组成)在Common Lisp中

来自分类Dev

Common Lisp中的'()vs()

来自分类Dev

#ifndef在Common Lisp中

来自分类Dev

在Common LISP中更改字节宽度中间流

来自分类Dev

Common Lisp中的功能范围

来自分类Dev

Common Lisp中的矩阵乘法

来自分类Dev

Common Lisp中的动态绑定

来自分类Dev

Common Lisp中的功能范围

来自分类Dev

Common Lisp 中的变量范围

来自分类Dev

Scheme或Common Lisp中的牛顿平方根方法

来自分类Dev

Scheme或Common Lisp中的牛顿平方根方法

来自分类Dev

在 common lisp 中获取“common-lisp:setf common-lisp:list* 未定义”

来自分类Dev

从Common Lisp中的列表中删除项目

来自分类Dev

从Common Lisp中的列表中删除项目

来自分类Dev

如何从 JSCL 方法调用 Common Lisp 代码

来自分类Dev

Jupyter和Common Lisp

来自分类Dev

〜|的含义 以Common Lisp格式

来自分类Dev

如何在Common Lisp中映射功能?

来自分类Dev

在Common Lisp中调用函数列表

来自分类Dev

关于Common Lisp中的MERGE函数

来自分类Dev

为什么FEXPR被丢弃在Common Lisp中?

来自分类Dev

Common Lisp中的条件Windows注释

来自分类Dev

Common Lisp中的环境目的是什么?

来自分类Dev

在Common Lisp中创建隐藏文件

来自分类Dev

从Common Lisp中的SQLite捕获错误