下面是我编写的一些代码,使用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中做这件事的惯用方式是什么。
这就是我喜欢上面的代码:
这是非常可读性。
这很容易写。
这里就是我不喜欢:
从任何地方访问
from
和to
领域但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中做这样的事情?做什么?
为什么不'(DEFN动作 - >编辑[G [行动英尺]'和'(condp =行动:提升 “助推”',还是我失去了一些东西 - 换句话说,为什么不首先解构fn参数? – birdspider
@birdspider谢谢,'condp'可能正是我需要的!我只用了几天的Clojure,因此我写了“Clojure中的Scheme”。发表一个答案!顺便说一句,在我的例子中,所有的记录看起来都有相同的两个参数。通常当我做这种事情时,他们会有所不同。我现在修改这个例子,因为我对这个成语很感兴趣对于如何解构变体记录 - 但在我的实际代码中,我会像使用通用模式一样利用你建议。:) –