我错过了关于defmulti和defmethod的重要观点。我读过几本书对defmulti的解释,我仍然很困惑。
我希望得到一个随机值,具体取决于它是否为交易或金额为100.00
我想调用(random-val)并返回avail-trans值或随机小数。我已经尝试将函数放在一个映射中,但是我得到了相同的值,用于avail-trans,一个\ B.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:multimethod'random-val'中没有方法用于调度值:null(NO_SOURCE_FILE:0)
答案 0 :(得分:7)
使用defmulti
创建多方法;你这样做了。 defmulti
需要名称和调度函数(以及文档字符串,如果您愿意,还有一些选项,但请忘记这些选项)。
(defmulti random-val identity)
当你使用defmethod
实现多方法时,你需要指定你正在实现的多方法的名称,它应该匹配的调度值,然后是函数tail(arglist加上你想要它做的任何事情) )。
(defmethod random-val :trans [t] (random-trans))
(defmethod random-val :amt [t] (random-amt))
您收到java.lang.IllegalArgumentException: No method in multimethod 'random-val' for dispatch value: null (NO_SOURCE_FILE:0)
因为当您分配的random-val
,:val-type
的发送功能应用于任何其他关键字时,它会为您提供null
。当Clojure试图查找匹配该调度值的方法时,它会失败。
但是即使它没有在那里失败,你定义的方法也有0个arity(没有值),所以你也需要修复它(在上面完成)。
最后,这似乎不适合协议。只需使用两个单独的函数random-amount
和random-trans
。
另请注意,Clojure's website对多方法有很好的解释。
答案 1 :(得分:1)
每次使用“\B
”时,您都会获得相同的值,因为您在地图map-val
中将其关联时正在评估该函数,从而绑定值B
永远反对map-val中的键':trans',而不是函数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)))