如何使用类型提示创建一个具有可变数量的args的Clojure多方法?

时间:2012-04-17 07:49:49

标签: clojure multimethod

我正在尝试使用类型提示来区分两种单方法。

例如,add-vertex正在包装一个可以获取可变数量的args的Java方法,所以我在这里尝试使add-vertex取零,一或两个args ......

(defmulti add-vertex (fn [& args] (map class args)))
(defmethod add-vertex [] (add-vertex nil nil))
(defmethod add-vertex Integer [id] (add-vertex id nil))
(defmethod add-vertex Map [props] (add-vertex nil props))
(defmethod add-vertex [Integer Map] [id props]
  ((let [vertex (. *g* addVertex id)]
    (when props
      (apply set-props vertex (interleave (map name (keys props)) (vals props))))
    vertex)))

请注意,有两个singe-arg函数 - 每个函数采用不同的类型(id是Java Integer,props是Java Map)。我是Clojure的新手所以我怀疑我做错了。

2 个答案:

答案 0 :(得分:2)

以下是您要执行的操作的代码:

(defmulti add-vertex (fn [& args] (map class args)))
(defmethod add-vertex [] [] (add-vertex nil nil))

;; You could also use java.lang.Integer here, but numbers are Longs by default
(defmethod add-vertex [java.lang.Long] [id] 
                                       (add-vertex id nil))

;; I assume you are using a clojure map ie {:1 2}
(defmethod add-vertex [clojure.lang.PersistentArrayMap] [props] 
                                                        (add-vertex nil props))

(defmethod add-vertex [java.lang.Long clojure.lang.PersistentArrayMap] [id props] ...)

但正如你所看到的那样,这会让课程变得非常混乱。

另一种解决方案可能是做这样的事情:

(defn dispatch-fn
  ([] :empty)
  ([a] (cond
         (number? a) :number
         (map? a)    :map
         :else       :error))
  ([a b] (if (and (number? a) (map? b))
             :number-and-map
             :error))
  ([a b & args] :error))

(defmulti add-vertex dispatch-fn)
(defmethod add-vertex :empty [] (add-vertex nil nil))
(defmethod add-vertex :number [id] (add-vertex id nil))
(defmethod add-vertex :map [props] (add-vertex nil props))
(defmethod add-vertex :number-and-map [id props] ...)
(defmethod add-vertex :error [& args] ...)

答案 1 :(得分:0)

您没有使用类型提示,而是将类文字编写为将用于评估调度函数的值。你的问题是,你不能在矢量中包含所有类型 - 即使只有一个类型。

我热烈建议你read up多方法。

相关问题