我有一个使用多种方法,并会非常喜欢重载函数(在这种情况下,多功能),这样我可以在一个高阶函数传递,以帮助测试,例如一些代码。
这里的例子:
(ns multi)
(defn my-print [m] (println "The colour is" (:colour m)))
(defmulti which-colour-mm (fn [m f] (:colour m)))
(defmethod which-colour-mm :blue [m f] (f m))
(defmethod which-colour-mm :red [m f] (f m))
(defmethod which-colour-mm :default [m f] (println "Default: Neither Blue nor Red"))
(defn which-colour
([m] (which-colour-mm m my-print))
([m f] (which-colour-mm m f)))
(which-colour {:colour :blue :object :ball})
(which-colour {:colour :yellow :object :ball})
(which-colour {:colour :blue :animal :parrot} (fn [m] (println "The " (:animal m) "is" (:colour m))))
所以我DEFN提供的元数超载,但我不知道是否defmethod支持这样的事。 (我想你不会想这样做,每个defmethod声明。)
这是最合适的(我敢说, 惯用语 )的方法,或者是有没有更好的办法?
这是完全正常的。 有“用户”界面和文库的“类型”的接口。 它们可以是相同的,但他们没有。
“用户”界面是你的情况which-colour
。 “类型”的接口是which-colour-mm
(好吧,不是真的,但只是为参数的缘故)。 库的用户并不需要了解的多方法。
在另一方面有人提供了一个新的颜色-比如:purple
-不必在乎多参数数量样板。 这是在为他处理which-colour
。
这是一个完全有效的设计!
不过,当然有一个价格标签:假设你有一个颜色,其中有一些更perfomant的方式做的事情......现在,你被锁定到一个可能较慢接口。
为了澄清这一点:假设你有一个采集接口。 你提供了一个功能- conj
-它允许用户将元素添加到集合中。 它的实现是这样的:
(defn conj
[coll & elements]
(reduce conj1 coll elements))
conj1
是“类型”接口(例如一个多方法或协议功能):它增加了一个元件到集合中。 因此,有人提供一个新的集合类只实现增加一个参数的简单情况。 并自动将新类型也将支持添加多个元素。
但是,现在假设你有一个集合类型,允许更快的方法来添加几种元素不仅仅是增加一个接一个。 这种能力现在不能使用。
所以,你做多方法/协议功能的功能conj
本身。 现在集合可以用更快的方式。 但是每个实现必须提供多个元素的样板。
这是一个权衡和高达你的决定。 没有正确的方式(TM)。 两者都可以被认为是地道的。 (虽然我个人会尝试尽可能经常去的第一个。)
因人而异。
编辑:没有派遣值编码的多元数方法的一个例子。
(defmulti which-colour-mm (fn [m & args] (:colour m)))
(defmethod which-colour-mm :blue
([m] (print m))
([m f] (f m)))
你可以做,使用多方法如下面的例子:
(defmulti which-colour-mm (fn [m & args] [(count args) (:colour m)]))
(defmethod which-colour-mm [0 :blue] [m] (print m))
(defmethod which-colour-mm [1 :blue] [m f] (f m))
user=> (which-colour-mm {:colour :blue :object :ball})
{:colour :blue, :object :ball}nil
user=> (which-colour-mm {:colour :blue :object :ball} print)
{:colour :blue, :object :ball}nil
基本上你可以在任何调度,无论是类型和参数的个数数必须是consistent..like这样的:
(defn- map-classes [an-object]
(let [cmap
{1 :thing
2 666
3 "yada"}
the-class (class an-object)]
(get cmap an-object the-class)))
(defn- mk-class [& args] (map #(map-classes %) args))
(defmulti play-thing mk-class )
(defmethod play-thing [:thing] [v] (= 1 v))
(defmethod play-thing [666] [v] (= 2 v))
(defmethod play-thing ["yada" String] [v x] (str x v))
可能性是无止境