任意类型说明符上的 Defmethod?

问题描述 投票:0回答:3

我想做的是:

(defgeneric fn (x))

(defmethod fn ((x (integer 1 *)))
    "Positive integer")

(defmethod fn ((x (integer * -1)))
    "Negative integer")

我想要一个可以与任意类型说明符一起使用的泛型函数,包括基于列表的类型说明符,例如

(and x y)
(or x y)
(satisfies p)
等。现在,当我尝试运行上述代码时,我得到一个“无效”专家”错误。一些研究表明
defgeneric
被设计为与 CLOS 一起使用,而不是与任意类型说明符一起使用。 Common Lisp 中是否有一个类似于 defgeneric 的系统,可以让我获得任意类型说明符所需的行为,而不仅仅是类?

types lisp common-lisp
3个回答
10
投票

没有什么 CLOS 能够提供这样的功能。

它实际上也不太适合 CLOS。考虑一下以下内容,我们有以下通用函数的调用:

(generic-function-foo 2)

现在我们为以下类型定义了方法:

(integer 0 9)
(integer 1 9)
(integer 0 99)
(integer 1 99)
(integer -1000 1000)
(or (satisfies evenp) (integer 0 30))
(satisfies evenp)
(satisfies divisible-by-two)
(satisfies all-numbers-which-are-in-my-list-of-numbers)

应该运行所有都匹配 2 的方法中的哪一个?如果我打电话给

CALL-NEXT-METHOD
,下一个会是哪一个?

现在我们可以说按源中的外观对它们进行排序。但在 Common Lisp 中,您可以在运行时添加、删除或重新定义方法。该行为或多或少是随机的。

我们需要一些其他的冲突解决方案。例如:

  • 手动声明优先级
  • 某种优先级值
  • 运行时错误,用户有机会选择一个
  • 一种类型语言,提供顺序
  • 一起放弃订单

已经尝试为 CLOS 提供更具表现力的调度。不过,我不知道向 CLOS 添加类型。请参阅谓词调度过滤调度

除此之外,我会寻找一个基于规则的系统,但这通常与 CLOS(Common Lisp 对象系统)有很大不同,除非它以某种方式集成。


9
投票

Common Lisp 定义了两个相关但不相同的层次结构:类型层次结构和类层次结构。每个类都是一种类型,但反之则不然——有些类型不是类。例如,

integer
string
是类,因此也是类型。另一方面,
(integer 1 *)
(satisfies evenp)
是类型,但不是类。

> (type-of "toto")
(SIMPLE-BASE-STRING 4)
> (class-of "toto")
#<BUILT-IN-CLASS STRING>

参数专门化器 - 您在

defmethod
中参数后面放置的内容 - 只能是类名称(或
(eql value)
形式)。由于
(integer 1 *)
不是类名,因此 Common Lisp 不允许您的代码。有一个很好的理由:编译器总是能够确定类层次结构,而类型语言对此来说太强大了:

(defun satisfies-the-collatz-conjecture (n)
  (cond
    ((<= n 1) t)
    ((evenp n) (satisfies-the-collatz-conjecture (/ n 2)))
    (t (satisfies-the-collatz-conjecture (+ 1 (* n 3))))))

(subtypep 'integer '(satisfies satisfies-the-collatz-conjecture))
NIL ;
NIL

如果你真的需要你的代码是模块化的,你需要首先将你的值分类为可以制作成专用程序的东西,然后对其进行分派:

(defmethod fn-generic (x (sign (eql 'positive)))
  "Positive integer")

(defmethod fn-generic (x (sign (eql 'negative)))
  "Negative integer")

(defun classify (x)
  (cond
    ((< x 0) 'negative)
    ((= x 0) 'null)
    ((> x 0) 'positive)))

(defun fn (x)
  (fn-generic x (classify x)))

2
投票

您实际上似乎在寻找的是模式匹配,就像在 ML 或 Erlang 中一样。这是与 dispatch 相当不同的概念,尽管它们具有相似的目的。

Common Lisp 的一个流行模式匹配库是 optima(可从 Quicklisp 获得)。

© www.soinside.com 2019 - 2024. All rights reserved.