什么是Clojure的可折叠系列?

时间:2018-02-28 14:17:43

标签: clojure reducers

我是Clojure的初学者,在尝试阅读Reducers时,我发现了一些名为可折叠集合的内容。

他们提到矢量和地图是可折叠的集合,但不是列表。

我试图理解什么是可折叠集合,为什么矢量和地图是可折叠的?

我没有找到任何可折叠收藏的定义或解释。

2 个答案:

答案 0 :(得分:3)

答案就在文档中,如果不是那么清楚:

  

此外,一些集合(持久性向量和地图)是   可折叠。减速器上的折叠操作执行减少   平行...

这个想法是,通过现代硬件,减少"像求和矢量的所有元素的操作可以并行完成。例如,如果对400K长度向量的所有元素求和,我们可以将它们分成4组100K块,并行求和,然后将4个小计组合成最终答案。这比仅使用单个线程(单个cpu核心)快大约4倍。

Reducers位于clojure.core.reducers命名空间中。假设我们定义了以下别名:

( ns demo.xyz
  (:require [clojure.core :as core]
            [clojure.core.reducers :as r] ))

clojure.core相比,我们有:

core/reduce   <=>   r/fold     ; new  name for `reduce`
core/map      <=>   r/map      ; same name for `map`
core/filter   <=>   r/filter   ; same name for `filter`

因此,命名并不是最好的。 reduce位于clojure.core命名空间中,但reduce命名空间中没有clojure.core.reducers。相反,fold中有一个名为clojure.core.reducers的类似工作的函数。

请注意,fold是用于组合数据列表的历史名称,与我们的求和示例一样。 See the Wikipedia entry了解更多信息。

因为折叠以非线性顺序访问数据(这对于链表来说非常低效),所以折叠只适用于随机访问数据结构,如矢量)。

更新#1

说完上面的话,请记住这样的格言:“过早优化是万恶之源。”#34;以下是8核机器上(vec (range 1e7))的一些测量值,即10M条目:

(time (reduce + data))

"Elapsed time: 284.52735 msecs"
"Elapsed time: 119.310289 msecs"
"Elapsed time: 98.740421 msecs"
"Elapsed time: 100.58998 msecs"
"Elapsed time: 98.642878 msecs"
"Elapsed time: 105.021808 msecs"
"Elapsed time: 99.886083 msecs"
"Elapsed time: 98.49152 msecs"
"Elapsed time: 99.879767 msecs"

(time (r/fold + data))

"Elapsed time: 61.67537 msecs"
"Elapsed time: 56.811961 msecs"
"Elapsed time: 55.613058 msecs"
"Elapsed time: 58.359599 msecs"
"Elapsed time: 55.299767 msecs"
"Elapsed time: 62.989939 msecs"
"Elapsed time: 56.518486 msecs"
"Elapsed time: 54.218251 msecs"
"Elapsed time: 54.438623 msecs"

Criterium报道:

reduce   144 ms
r/fold    72 ms

更新#2

Rich Hickey谈到了传感器/减速器的设计at the 2014 Clojure Conj。您可能会发现这些细节很有用。基本思想是将折叠委托给每个集合类型,该集合类型使用其实现细节的知识来有效地执行折叠。

由于哈希映射在内部使用向量,因此它们可以有效地并行折叠。

答案 1 :(得分:0)

盖伊斯蒂尔(Guy Steele)有这样的谈话,它早于减速器,可能只是为他们提供灵感。 https://vimeo.com/6624203