我正在编写一个 Clojure 库来使用四边数据结构生成 Voronoi 图,如本研究论文中所述。我使用 refs 来表示边缘记录,但我想将代码更改为纯粹的,原因如下:
dosync
中。问题在于,由于将数据结构传递给每个函数,纯代码极其重复。这是一个例子:
(defn- bubble-up [qeds cross]
(loop [qeds qeds
cross cross]
(let [l-edge (first-hit qeds cross (q/r-prev qeds cross) q/o-next)
r-edge (first-hit qeds cross (q/o-prev qeds cross) q/o-prev)
l-valid (above? qeds l-edge cross)
r-valid (above? qeds r-edge cross)]
(when (or l-valid r-valid)
(let [[qeds new-cross]
(if (or (not l-valid)
(and r-valid
(in-circle? (dest qeds l-edge) (org qeds l-edge) (org qeds r-edge)
(dest qeds r-edge))))
(connect qeds r-edge (q/sym cross))
(connect qeds (q/sym cross) (q/sym l-edge)))]
(recur qeds new-cross))))))
我尝试过各种其他方法,包括:
在 Clojure(script) 中是否有一个标准的、惯用的方法来处理这样的情况?
在 Clojure(script) 中是否有一个标准的、惯用的方法来处理这样的情况?
无法对所有人做出判断,但我会让事情保持原样。 并且冒着陈述显而易见的风险,如果可以在超过 2 个位置看到某些特定的形式集(不仅仅是单个函数调用),那么它可能应该被提取到自己的函数中。但所提供的代码没有类似的东西。
如果您不喜欢这种重复,以至于必须做一些事情,作为替代方案,您可以创建一个类似于 partial
但颠倒过来的函数:
(defn bind [obj & fns]
(mapv #(prepare % obj) fns))
然后将其用作:
(let [[first-hit r-prev o-prev above?]
(bind qeds first-hit o/r-prev o/o-prev above?)]
l-edge (first-hit cross (r-prev cross) q/o-next)
r-edge (first-hit cross (o-prev cross) q/o-prev)
l-valid (above? l-edge cross)
r-valid (above? r-edge cross)]
...)
值不值得,就看你自己了。我可能不会这样做,除非有更多类似的行重复使用相同的功能。
作为另一种选择,您可以使用动态变量来存储图形。但在某些方面,它可能比基于 refs/atoms 的解决方案更糟糕。