是否有可能超载的元数Clojure的多的方法呢?(Is it possible to overloa

2019-07-29 03:20发布

我有一个使用多种方法,并会非常喜欢重载函数(在这种情况下,多功能),这样我可以在一个高阶函数传递,以帮助测试,例如一些代码。

这里的例子:

(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声明。)

这是最合适的(我敢说, 惯用语 )的方法,或者是有没有更好的办法?

Answer 1:

这是完全正常的。 有“用户”界面和文库的“类型”的接口。 它们可以是相同的,但他们没有。

“用户”界面是你的情况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)))


Answer 2:

你可以做,使用多方法如下面的例子:

(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


Answer 3:

基本上你可以在任何调度,无论是类型和参数的个数数必须是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))

可能性是无止境



文章来源: Is it possible to overload Clojure multi-methods on arity?