Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 重用多方法的分解结构_Clojure - Fatal编程技术网

Clojure 重用多方法的分解结构

Clojure 重用多方法的分解结构,clojure,Clojure,有没有办法在一个多方法中的多个方法之间重用一个分解结构 (defmulti foo (fn [x] (:a x))) (defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e)) (defmethod foo :2 [a] "") (defmethod foo :3 [a] "") 现在这是一个简单的例子,但假设我们有一个更复杂的嵌套映射的分解,我想在我所有的defmethodsforfoo上使用它。我该怎么做呢?一个实用的解决方案是只使用每

有没有办法在一个多方法中的多个方法之间重用一个分解结构

(defmulti foo (fn [x] (:a x)))
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e))
(defmethod foo :2 [a] "")
(defmethod foo :3 [a] "")

现在这是一个简单的例子,但假设我们有一个更复杂的嵌套映射的分解,我想在我所有的
defmethods
forfoo上使用它。我该怎么做呢?

一个实用的解决方案是只使用每个方法所需的键。关于解构,需要注意的一点是,不必绑定要解构的集合中的每个值。假设每个传递给这个多重方法的映射都包含键
:a
:e
,但是每个方法只需要几个键。你可以这样做:

; note: a keyword can act as a function; :a here is equivalent to (fn [x] (:a x))
(defmulti foo :a)  
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e))
(defmethod foo :2 [{:keys [b d]}] (str b d))
(defmethod foo :3 [{:keys [c e a]}] (str a c e))
(defmethod draw-ui :play [ui game screen]
  (let [tiles (get-in game [:world :tiles])
    ...
如果您有一个复杂的嵌套结构,并且希望获取特定的值,那么您可以省略不需要的键,或者,根据您的用例,函数定义中的
let
绑定可能更容易阅读。史蒂夫·洛什(Steve Losh)的故事浮现在脑海中——在用Clojure从头开始编写一个类似流氓的文本冒险游戏时,他使用嵌套地图来表示游戏的状态。最初,他编写了一些使用解构来访问“游戏状态”地图内部位的函数,例如:

(defmethod draw-ui :play [ui {{:keys [tiles]} :world :as game} screen]
  ...
但是后来,他决定通过将解构拉到let绑定中来提高代码的可读性:

(defmethod draw-ui :play [ui game screen]
  (let [world (:world game)
        tiles (:tiles world)
        ...
关键是,如果您使用的是深度嵌套的结构,并且希望代码保持简单(特别是如果您正在编写一个包含多个方法的多方法,其中多个方法使用相同的结构作为参数),那么您可能希望避免使用析构,而只是使用
let
绑定来获取所需的片段。是从嵌套集合中简洁地获取值的好工具。回到Clojure洞穴的例子,如果Steve只需要瓷砖,他可以做如下事情:

; note: a keyword can act as a function; :a here is equivalent to (fn [x] (:a x))
(defmulti foo :a)  
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e))
(defmethod foo :2 [{:keys [b d]}] (str b d))
(defmethod foo :3 [{:keys [c e a]}] (str a c e))
(defmethod draw-ui :play [ui game screen]
  (let [tiles (get-in game [:world :tiles])
    ...
就我个人而言,我发现这比用
{{:keys[tiles]}:world:as game}
来搞乱函数参数要容易得多


编辑:

如果确实希望避免对每个多方法重复解构,并且希望每个方法都具有相同的可用绑定,则可以编写宏:

(defmulti foo :a)

(defmacro deffoomethod [dispatch-val & body]
  `(defmethod foo ~dispatch-val [{:keys [~'a ~'b ~'c ~'d ~'e]}]
     ~@body))

(deffoomethod 1 (str a b c d e))
(deffoomethod 2 (str b d))
(deffoomethod 3 (str a c e))

(foo {:a 1 :b 2 :c 3 :d 4 :e 5})
;=> "12345"

(foo {:a 2 :b \h :d \i})
;=> "hi"

(foo {:a 3 :b \x :c 0 :d \x :e 0})
;=> "300"

不过,我不推荐这种方法,因为它破坏了宏观卫生。使用此宏的任何人都必须记住,它将符号
a
通过
e
绑定到参数中相应的键,这可能会有问题。

挑剔:根据,关键字应该以字母或*、+、!、-、ux开头,还是?@Dave-写得不错!