在Clojure中转换增长矢量的惯用法

时间:2016-06-05 14:14:22

标签: clojure pipeline idiomatic

说我在Clojure中有一个向量:

(def myvec (atom (vector 1)))

我有这个函数为向量添加新值:

(defn inc-myvec! []
  (swap! myvec conj (inc (last @myvec))))

假设在某个触发器上不时调用此函数。让我们触发几次。

(dotimes [i 5] (inc-myvec!))
@myvec
;=> [1 2 3 4 5 6]

现在,如果我想从该向量中的每个元素中减去1,我会做这样的事情:

(def myvec2 (atom (mapv dec @myvec)))
@myvec2
;=> [0 1 2 3 4 5]

这当然不是很好,因为我必须在myvec的每次更改时都这样做。它也是浪费,因为它在每次变化时都会产生整个矢量。我们可以做得更好。让我们实现观察者模式并仅计算附加的最后一个值:

(defn watcher [_ _ _ new-myvec]
  (swap! myvec2 conj (dec (last new-myvec))))
(add-watch myvec :watcher watcher)

这还不错。但理想情况下,我希望观察者在另一个线程中为初学者操作。是否有更好的,更惯用的方法来处理这种转换,在这种转换中你基本上需要在输入数据流到达时对其进行反应并将其转换为其他数据流?

1 个答案:

答案 0 :(得分:3)

如果您更多地解释一般用例,可能更容易指出正确的方向。你真的需要一个向量作为输出(即随机访问能力)吗?或者你只是想要一种方法来转换来自一个来源的数据并把它放在其他地方?

如果你实际上不需要随机访问矢量,我会说使用core.async和频道是最好的方法。通过这种方式,您可以使用特定的线程或循环来处理数据发布,转换和消费的每个步骤,只需在它们之间放置一个通道即可。

以下是一些有关core.async的好文章(但如果你做一个快速的谷歌,还有更多的东西):

希望这有帮助!