2014-11-23 79 views
4

我想要做的是这样的:任意类型说明符的Defmethod?

(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的系统,它会让我得到我想要的任意类型说明符的行为,而不仅仅是类?

+0

零是正面还是负面? – 2014-11-23 04:58:45

+0

@RainerJoswig修正了,但并没有真正改变问题的目的。 – 2014-11-23 05:01:31

+0

是真实的,但它暴露了这样一个功能的问题。如果两种方法匹配:使用哪一种?方法不能被排序...对于零,两种方法都是匹配的。哪一个应该被使用? – 2014-11-23 05:09:24

回答

7

Common Lisp定义了两个相关但不相同的层次结构:类型层次结构和类层次结构。每个类都是一个类型,但反过来不是真的 - 有类型不是类。例如,integerstring是类,因此也是类型。另一方面,(integer 1 *)(satisfies evenp)是类型,但不是类。

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

参数specialisers - 您在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 

如果你真的需要你的代码是模块化的,您需要首先你的价值观分为东西可以做成一个specialiser,然后对调度:

(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))) 
6

没有什么 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中,您可以在运行时添加,删除或重新定义方法。行为或多或少是随机的。

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

  • 手动声明优先
  • 某种优先级值
  • 有用于用户有机会运行时错误的选择一个
  • 一个类型的语言,它提供了一个顺序
  • 给予up order all together

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

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

1

你实际上似乎有什么要寻找的是模式匹配,像ML或二郎。这是一个非常不同的概念,从调度,虽然他们有类似的目的。

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