3

How to use the type index to create a multimethod Clojure with a variable number...

 2 years ago
source link: https://www.codesd.com/item/how-to-use-the-type-index-to-create-a-multimethod-clojure-with-a-variable-number-of-args.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to use the type index to create a multimethod Clojure with a variable number of args?

advertisements

I'm trying to use type hinting to differentiate between two single-arg methods.

For example, add-vertex is wrapping a Java method that can take a variable number of args, and so here I am trying to make add-vertex take zero, one, or two 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)))

Notice there are two singe-arg funcs -- each taking a different type (id is a Java Integer and props is a Java Map). I'm new to Clojure so I suspect I'm doing this totally wrong.


Here is the code for what you are trying to do:

(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] ...)

But as you can see this gets pretty messy with the classes.

An alternate solution might be to do something like this:

(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] ...)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK