让我们假设我们有一个描述移动球的数据结构。
(def moving-ball {:position [100 100]
:velocity [1 3]
:acceleration [0 0]})
编写一个解构地图,更新属性并返回新地图的update-fn是不是惯用?像那样:
(defn update-acceleration
[{:keys [position] :as s} mx my]
(let
[[x y] position
dx (- mx x)
dy (- my y)
dir (normalize [dx dy])]
(assoc s :acceleration dir)))
或者分开这些功能会更好吗?
(defn direction
[[x y] mx my]
(let [dx (- mx x)
dy (- my y)]
(normalize [dx dy])))
(defn update-map
[{:keys [position] :as s} mx my]
(assoc s :acceleration (direction position mx my)))
第一个耦合到数据结构(因此不能真正重用),但第二个需要更多代码。有没有更好的方法呢?
答案 0 :(得分:3)
如果我们改进数据呈现给函数的方式,我们可以从地图数据结构的纠缠中有用地提取函数direction
。这与重构人员调用introduce (or extract) parameter object和extract method的内容有关。
问题是[x y]坐标呈现的不均匀方式:有时是两个数字,有时是一对。如果我们将它们全部表示为对,我们可以更好地掌握函数的作用。
如果我们对direction
函数执行此操作,则会变为......
(defn direction [[x y] [mx my]]
(let [dx (- mx x)
dy (- my y)]
(normalize [dx dy])))
......我们可以减少到......
(defn direction [from to] (normalize (mapv - to from)))
现在我们有了一个我们可以理解的功能。因为它可能会在update-acceleration
内以及在其中使用,所以它是可行的。 (与无意义的参数名称相同的功能并不那么令人信服)。
本着同样的精神,我们可以改革update-acceleration
:
(defn update-acceleration [{:keys [position] :as s} [mx my]]
(let
[[x y] position
dx (- mx x)
dy (- my y)
dir (normalize [dx dy])]
(assoc s :acceleration dir)))
......减少到......
(defn update-acceleration [s m]
(assoc s :acceleration (normalize (mapv - m (:position s)))))
......或者,使用direction
函数,......
(defn update-acceleration [s m]
(assoc s :acceleration (direction (:position s) m)))
您可以从任何语言的重构中获益。 Clojure的序列库扩大了效果。 (其他序列库可用:任何Lisp或其他功能语言,Smalltalk,C#,... YMMV)
P.S。
我猜测normalize
返回同一方向的单位向量。以下是使用序列函数执行此操作的一种方法:
(defn normalize [v]
(let [length (->> v
(map #(* % %))
(reduce +)
Math/sqrt)]
(mapv #(/ % length) v)))
这绝对值得提取。事实上,我很想退出length
:
(defn length [v]
(->> v
(map #(* % %))
(reduce +)
Math/sqrt))
...并将normalize
定义为......
(defn normalize [v]
(let [l (length v)] (mapv #(/ % l) v)))
小警告:mapv
将在其最短的参数上静默停止,因此您可能需要检查其所有参数的长度是否相同。
答案 1 :(得分:1)
惯用语是使用update-in
。见http://clojuredocs.org/clojure_core/clojure.core/update-in
update-in
将使用您调用方向的函数。函数update-in获取移动球的旧值,并将其作为更新函数的参数。所以你必须相应地改变方向。