2014-11-23 113 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獲得)。