2013-10-28 32 views
0

我有一個協議叫做IExample和我定義了一個記錄類型A實現它:clojure:我可以定義一個隱式轉換possility嗎?

(defprotocol IExample 
    (foo [this] "do something") 
    (bar [this] "do something else")) 

(defrecord A [field1 field2] 
    IExample 
    (foo [this] 
    (+ field1 field2)) 
    (bar [this] 
    (- field1 field2))) 

比方說,我想對另一個(基本)類型B實施這一協議,但我知道如何從轉換BA

(defn B-to-A 
    "converts a B object to an A object" 
    [Bobj] ...) 

,因爲我有這樣的轉變,我可以委派對B到的IExample協議 的所有呼叫3210協議上的A通過委派它們:

(extend B 
    IExample { 
    :foo (fn [this] (foo (B-to-A this))) 
    :bar (fn [this] (bar (B-to-A this)))}) 

然而,這似乎非常多的樣板(特別是對於較大的協議) 未Clojure的-慣用。

我怎麼能告訴Clojure的只是每一個 功能IExample被稱爲B對象時隱式轉換BA,使用B-to-A功能?

回答

2

就樣板而言,您可以編寫一些宏爲您編寫所有樣板文件。另一方面,你可以在這裏再次看看你的設計。

我們這裏有3件東西(類型):ABIExample。然後我們在這些事情之間有2個關係:1)a-to-example : A -> IExample 2)b-to-a : B -> A並且由此我們可以通過使用組合即compose b-to-a with a-to-example : B -> IExample獲得第三關係。現在,如果我們嘗試將此設計移到協議中,我們會發現它不是簡單的翻譯,因爲協議不會像上述設計中討論的那樣直接組成,而是我們可以使用如下所示的中間協議IToExample

(defprotocol IExample 
    (foo [this] "do something") 
    (bar [this] "do something else")) 

(defprotocol IToExample 
    (to-example [this] "convert to IExample")) 

(defrecord A [field1 field2] 
    IExample 
    (foo [this] 
    (+ field1 field2)) 
    (bar [this] 
    (- field1 field2)) 
    IToExample 
    (to-example [this] this)) 

(deftype B []) 
(defn b-to-a [b] (A. ....)) 
(extend B 
    IToExample {:to-example b-to-a}) 

我們做了什麼,我們在我們的設計中將-> IExample表示爲具有一個功能的IToExample協議。因此,我們得到:

  • a-to-example : A -> IExample通過實施IToExample對於A
  • b-to-a : B -> A由正常功能
  • compose b-to-a with a-to-example : B -> IExample通過實施IToExample的B,使用B-到一個。
1

這取決於。如果您看看clojure核心seq函數,您可能會注意到接口只有4種方法,並且整個「公共」序列庫由(更多)函數定義,這些函數調用(some-internal-function (seq argument)) - 並且它們傾向於明確記錄也是這樣做的。從概念上講,有一個像IExample接口這樣的協議,以及一個附加協議,該協議描述seq函數將某種類型轉換爲實現ISeq的某些內容。

這是一個特別有用的策略,如果數據類型只需要實現幾個方法(所以IExample可能很小)並且在協議上作用的算法數量很大(因爲您可以根據常規功能)。

相關問題