作为多方法的一部分修改参数

时间:2018-07-25 21:46:06

标签: clojure clojurescript

编写多方法来修改传入参数作为调度的一部分的惯用方式是什么?

在这种情况下,我想删除一个参数:

(defmulti do-update ???)

(defmethod do-update :set-cursor [state x y]
  (assoc state :cursor [x y]))

(defn post [action & args]
  (swap! some-state do-update action args))

(post :set-cursor 0 0)

这里的dispatch-fn将负责读取action关键字转发(cons state args)作为方法的参数。

这种方法的替代方法是创建一个调度图。

(defn set-cursor [state x y])

(def handlers
  {:set-cursor set-cursor})

(defn dispatch [action & args]
  (let [handler (action handlers)]
    (apply swap! some-state handler args)))

但是,最好在没有映射的情况下针对它们的相应操作自动注册这些处理程序。

3 个答案:

答案 0 :(得分:5)

方法接收与分派函数相同的参数是多方法设计的一部分。如果这些方法对仅用于分派的某些参数不感兴趣,那么在方法实现中忽略它们是完全可以的,而且一点也不奇怪:

(def some-state (atom {:cursor [-1 -1]}))

(defmulti do-update
  (fn [state action x y]
    action))

;; ignoring the action argument here:
(defmethod do-update :set-cursor [state _ x y]
  (assoc state :cursor [x y]))

;; added apply here to avoid ArityException in the call to do-update:
(defn post [action & args]
  (apply swap! some-state do-update action args))

(post :set-cursor 0 0)

@some-state
;= {:cursor [0 0]}

请注意,为使do-updateswap!一起使用,dispatch参数排在第二位。

答案 1 :(得分:1)

您不能直接问该方法,分配函数的哪个输入导致它选择调用此方法,因为分配方法只是函数,所以可以!

您可以从其分派到的方法中再次调用分派函数。只要您的调度功能是纯函数,那么它将是可靠的。如果没有...

因此,如果您以此定义yoru dipatch函数???(是???是有效的函数名称)

user=> (defn ??? [x] (inc x))
#'user/???

和您的多重方法如下:

user=> (defmulti foo ???)

,然后在方法中再次调用调度函数:

 (defmethod foo 1 [x] 
    (str "I was dispatched from " x 
         " and i will use " (??? x) 
         " to do my good work"))

您可以重建调度功能的动作,而不必维护独立的功能/地图/事物。

user=> (foo 0)
"I was dispatched from 0 and i will use 1 to do my good work"

答案 2 :(得分:1)

虽然核心语言不支持此功能,但是您可以使用一些“重写”宏来覆盖所需的语义:

(defmacro defupdatemulti [name] 
  `(defmulti ~name (fn [state# action# & args#] action#)))

(defmacro defupdatemethod [name action [state & args] & body] 
  `(defmethod ~name ~action 
    [~state _# [~@args]] 
    ~@body))

并使用它:

(defupdatemulti do-update)

(defupdatemethod do-update :set-cursor [state x y] 
  (assoc state :cursor [x y]))

有了这个地方

(def some-state (atom {}))

(defn post [action & args]
  (swap! some-state do-update action args))

(post :set-cursor 0 0)

产生以下结果:

{:cursor [0 0]}

注意:尽管上述方法有效,但肯定不是习惯用法。