2016-04-08 53 views
3

下面是我编写的一些代码,使用clojure.core.match,它执行相当常见的编程任务。一个函数需要一些“命令”(或“对象”,“记录”或任何你喜欢称之为的东西),必须对每种类型做一些不同的事情,并且必须对它们进行解构以准确地确定要做什么以及不同的命令类型可能会以不同的方式解构:在Clojure中解构命令的习惯性方式

(defn action->edits [g action] 
    "Returns vector of edits needed to perform action in graph g." 
    (match action 
    [:boost from to] 
     [[:add-edge from to 1.0]] 
    [:retract from to] 
     [[:remove-edge from to]] 
    [:normalize from to]  ; a change has just been made to from->to 
     (map (fn [that] [:remove-edge from that]) 
      (successors-except g from to)) 
    [:recip-normalize to from] ; a change has just been made to from->to 
     [] 
    [:reduce-to-unofficial from to competitor] 
     [[:remove-edge from to] (make-competitive-edge from competitor])) 

我主要模仿了人们通常使用方案的pmatch宏。我想知道在Clojure中做这件事的惯用方式是什么。

这就是我喜欢上面的代码:

  • 这是非常可读性。

  • 这很容易写。

这里就是我不喜欢:

  • 从任何地方访问fromto领域但match宏内部是非常不可读的,而且容易出错。例如,要从大多数动作向量中提取from元素,请编写(action 1)。如果我添加了新的动作,那么该代码将会中断,并且现在在:recip-normalize中断。

  • match生成的代码效率低下:它通过重复抛出和捕获异常来进行搜索。它不会产生一个大的嵌套if

我尝试一点与代表命令,地图,但它似乎变得冗长,以及命令的名称并不突出好,大大降低了可读性:

(match action 
    {:action :boost :from from :to to} 
     [{:edit :add-edge :from from :to to :weight 1.0}] 
    {:action :retract :from from :to to} 
     [{:edit :remove-edge :from from :to to}] 
    . . .) 

可能未来版本的match将生成更好的代码,但现在生成的糟糕代码(以及缺乏对记录的支持)表明,在Clojure中,人们多年来一直在愉快地处理这种事情,而没有match。那么如何在Clojure中做这样的事情?做什么

+0

为什么不'(DEFN动作 - >编辑[G [行动英尺]'和'(condp =行动:提升 “助推”',还是我失去了一些东西 - 换句话说,为什么不首先解构fn参数? – birdspider

+0

@birdspider谢谢,'condp'可能正是我需要的!我只用了几天的Clojure,因此我写了“Clojure中的Scheme”。发表一个答案!顺便说一句,在我的例子中,所有的记录看起来都有相同的两个参数。通常当我做这种事情时,他们会有所不同。我现在修改这个例子,因为我对这个成语很感兴趣对于如何解构变体记录 - 但在我的实际代码中,我会像使用通用模式一样利用你建议。:) –

回答

0

我会利用clojure的内置destructuring facilities,因为我没有在这里看到core.match的要求 - 但我可能会错过一些东西。

例如:

(defn action->edits [g [action from to]] 
    (condp = action 
    :boost "boosting" 
    :retract "retracting" 
    :normalize-ksp-style (recur g [:boost from to]) 
    nil)) 

(action->edits 2 [:normalize-ksp-style 1 2]) 
;=> "boosting" 
+0

谢谢 - 这可能就是这个Clojure noob所需要的。三个问题:1)什么是“KSP风格”? ([This](https://en.wikipedia.org/wiki/Kerbal_Space_Program)?)2)如果他们有不同的参数,是否有简单的方法来解构不同的动作? 3)你通常会如何访问代码中其他地方的'from'和'to'字段? '(行动1)'和'(行动2)',总是去结构化,最好是使用地图而不是矢量,还有其他的东西? –

+0

@BenKovitz 1)是啊! 1只是测试ksp 1.1prerelease和你的问题与提升出现 - 无法抗拒。 2)你可以在(地图)键上进行解构(参见我提供的链接 - 向下滚动),3)可读性强的原因为什么不在'(let [[aft] action])中 - 但我想没有困难规则,(除了表演,那么你想'defrecord's) – birdspider