2011-12-17 31 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