2011-12-17 60 views
4

我錯過了關於defmulti和defmethod的一個重要觀點。我讀過幾本書對defmulti的解釋,但我仍然感到困惑。構建Clojure defmulti/defmethod

我想這取決於它是否是一個交易或者我想打電話給喜歡100.00

量(隨機VAL),要麼拿回播映反值或隨機小數量得到一個隨機值。我已經嘗試將這些函數放在地圖中,但是我得到了相同的值,以反轉a,b。

(def^:dynamic map-val {:trans (random-trans) :amt (random-amount)}) 

這是最少量的代碼來顯示我在做什麼,不工作。我會很感激任何指針或幫助。

(def^:dynamic avail-trans [\B \W \D \A]) 

(defn random-trans 
    [] 
    (nth avail-trans (.nextInt random (count avail-trans)))) 

(defn random-amount 
    [] 
    (float (/ (.nextInt random (count (range 1 10000))) 25))) 

以下是構造不正確,但我不知道爲什麼或如何來解決這個問題:

(defmulti random-val :val-type) 

(defmethod random-val :trans [] 
    (random-trans)) 

(defmethod random-val :amt [] 
    (random-amount)) 

調用(random-val :trans)導致此錯誤:

的java.lang。 IllegalArgumentException:多方法'random-val'中沒有用於分派值的方法:null(NO_SOURCE_FILE:0)

回答

7

使用創建multimethod;你做得對。 defmulti需要一個名稱和一個調度函數(和一個文檔字符串,加上一些選項,如果你願意,但忘了那些)。

(defmulti random-val identity) 

當您實現與defmethod的多方法,你需要指定你實現任何你想要它做的多重方法,調度值應該匹配,然後函數尾(arglist中加名)。

(defmethod random-val :trans [t] (random-trans)) 
(defmethod random-val :amt [t] (random-amt)) 

,因爲當你分配random-val的調度功能,:val-type被應用到任何其他關鍵字你得到java.lang.IllegalArgumentException: No method in multimethod 'random-val' for dispatch value: null (NO_SOURCE_FILE:0),它給你null。當Clojure試圖查找匹配該分派值的方法時,它失敗。

但即使它沒有失敗,您定義的方法有0個參數(不帶值),所以您也需要修復它(上面已完成)。

最後,這似乎不太適合協議。只需使用您的兩個單獨功能,random-amountrandom-trans

請注意,Clojure's website對multimethods有很好的解釋。

+1

我欣賞的答案非常多。這兩個答案(迄今爲止)比我在Clojure的網站上看到的要好。沒有明智的傢伙打算,但Clojure在我看來是「需要村莊」的語言/學習體驗之一。我從聽所有答案中得到一些東西。 – octopusgrabbus 2011-12-17 17:58:42

+0

你已經說服我不要將這個特殊的例子用於multimethods,但是爲了進行實驗,如果我重新安排了你的例子,我怎麼稱呼它呢? – octopusgrabbus 2011-12-17 18:09:54

+0

我不太確定你在問什麼;你的意思是,如果你想使用multimethods,你會怎麼做?我上面寫的代碼應該按照你的意圖工作。 – Isaac 2011-12-17 23:21:26

1

你得到每一次相同的值回無濟於事反「\B」,因爲你正在評估當您在地圖map-val它聯繫起來,從而綁定的值B永遠對按鍵的功能:在MAP-「反式」 val,而不是功能randon-trans本身。

如果你在map-val的函數分配中移除了parens,它就可以正常工作。那麼就沒有必要使用多方法,這可能不適合@ isaac-hodes所暗示的。

這對我的作品在REPL:

(def avail-trans [\B \W \D \A]) 
(def random (java.util.Random.)) 

(defn random-trans [] 
    (nth avail-trans (.nextInt random (count avail-trans)))) 

(defn random-amount [] 
    (float (/ (.nextInt random (count (range 1 10000))) 25))) 

; No parens around function names 
(def map-val {:trans random-trans :amt random-amount}) 

(println ((:trans map-val))) 
(println ((:amt map-val))) 
+0

謝謝,這很有幫助。我試圖讓和平報告中出現問題的地方。 – octopusgrabbus 2011-12-17 17:59:26