2010-09-19 29 views
2

我有一個名爲袋子的defrecord。它的行爲與要計數的項目列表相似。這有時被稱爲頻率或人口普查。我希望能夠做到以下幾點我如何獲得核心clojure函數與我的defrecords一起工作

(def b (bag/create [:k 1 :k2 3]) 
(keys bag) 
=> (:k :k1) 

我試過如下:

(defrecord MapBag [state]                                   
    Bag                                        
    (put-n [self item n]                                   
    (let [new-n (+ n (count self item))]                               
      (MapBag. (assoc state item new-n))))                              

    ;... some stuff 

    java.util.Map                                     
    (getKeys [self] (keys state)) ;TODO TEST                              

    Object                                       
    (toString [self]                                    
    (str ("Bag: " (:state self))))) 

當我嘗試要求它在REPL我得到:

java.lang.ClassFormatError: Duplicate interface name in class file compile__stub/techne/bag/MapBag (bag.clj:12) 

這是怎麼回事上?我如何在我的包包上獲得鑰匙功能?通過假設clojure的按鍵函數最終在地圖上調用getKeys(它的參數),我是否也會通過這種正確的方法來解決這個問題?

回答

4

Defrecord自動確保它定義的任何記錄參與ipersistentmap接口。所以你可以不用做任何事情就可以打電話給它。

所以,你可以定義一個記錄,並實例並調用鍵這樣的:

user> (defrecord rec [k1 k2]) 
user.rec 
user> (def a-rec (rec. 1 2)) 
#'user/a-rec 
user> (keys a-rec) 
(:k1 :k2) 

你的錯誤消息表明您聲明中的一個重複的是defrecord爲您提供免費的接口。我認爲它可能實際上都是。

是有一些原因,你不能只用你的目的一個普通的地圖嗎?使用clojure時,你可以儘量使用普通的香草數據結構。

編輯:如果出於某種原因你不想包括ipersistentmap,看看DEFTYPE。

+1

有趣。謝謝。有一個原因,這不是一個香草地圖。如果我對生活在行星上的人進行普查:我可能想要類似以下的東西:(得到行星地球)=> 80億(得到行星火星)=> 0。一個香草地圖將給我火星上的零個人,除非我使用得到行星火星0)。我不希望客戶必須知道這一點。 – 2010-09-19 03:33:14

3

Rob的答案當然是正確的;我發佈這篇文章是爲了迴應OP對此的評論 - 也許這對於deftype實現所需的功能可能會有所幫助。

我曾經寫了一個「默認地圖」爲Clojure的,其作用就像一個普通的地圖除了當被問及不存在裏面的關鍵,它返回一個固定的默認值的實現。代碼在this Gist

我不知道這是否會直接滿足您的使用情況下,雖然你可以用它做的事情一樣

user> (:earth (assoc (DefaultMap. 0 {}) :earth 8000000000)) 
8000000000 
user> (:mars (assoc (DefaultMap. 0 {}) :earth 8000000000)) 
0 

更重要的是,它應該給你一個什麼樣的參與寫這類的想法與deftype的東西。

再次,它基於clojure.core/emit-defrecord,所以你可以看看Clojure源代碼的那部分內容......它做了許多你不需要的東西(因爲它是一個準備宏擴展的函數 - 這裏面有很多語法引用等等,你必須直接使用代碼來剝離代碼),但它肯定是可能的最高質量信息源。 Here是Clojure 1.2.0版本的源代碼中的一個直接鏈接。

更新:我意識到

一件事可能是很重要的。如果你依賴特殊的類地圖類型來實現這種事情,那麼客戶端可能會將其定位到常規地圖中,並在此過程中失去「默認」功能(以及其他任何特殊功能)。只要你的類型維護的「地圖樣式」錯覺足夠完整,可以用作常規地圖,傳遞給Clojure的標準函數等等,我認爲可能沒有辦法解決這個問題。

因此,在某種程度上,客戶可能必須知道有一些「魔術」參與;如果他們對(:mars {...}){...}中沒有:mars)這樣的查詢得到正確的答案,他們將不得不記住merge這是一個常規地圖(merge-反過來可以正常工作)。

相關問題