Clojure Multimethods区分地图和地图列表

时间:2014-07-07 03:28:36

标签: clojure

我想编写一个可以处理特定事物(由地图表示)或这些地图列表的函数。

是否可以使用defmulti / defmethod?有人能指出我如何编写测试函数作为地图或地图列表的例子吗?

2 个答案:

答案 0 :(得分:5)

Multimethods将自动使用类层次结构,因此您只需打开类型:

(defmulti process class)

(defmethod process clojure.lang.IPersistentMap [m]
  (println "got map"))

(defmethod process clojure.lang.Sequential [s]
  (println "got sequential"))

(defmethod process :default [o]
  (println "got something else"))

在构建这样的案例时必须小心,以确保不会遇到满足两种情况的具体类型。如果是这样,那将是任意选择 - 使用prefer-method来定义首选项。 (另请注意,尽管您可以使用协议执行与上述完全相同的impl,但是没有相同的方法可以使用协议选择首选结果。)

或者您可以在检测您关注的案例时任意调整您的调度方法:

(defmulti process
  (fn [o] 
    (cond
      (map? o) :map
      (sequential? o) :sequential
      :else (class o))))

(defmethod process :map [m]
  (println "got map"))

(defmethod process :sequential [s]
  (println "got sequential"))

(defmethod process :default [o]
  (println "got something else"))

答案 1 :(得分:2)

你可以这样做:

(defmulti foo type)

(defmethod foo clojure.lang.IPersistentMap [m]
  (println "map"))

(defmethod foo clojure.lang.Sequential [m]
  (println "sequential"))

但是,使用具有条件的单个函数可能更清晰,例如

(if (map? m) 
  (deal with the map) 
  (deal with each map, e.g. by recursing over each element))