Clojure 中的可折叠集合是啥?

Posted

技术标签:

【中文标题】Clojure 中的可折叠集合是啥?【英文标题】:What is a foldable collection in Clojure?Clojure 中的可折叠集合是什么? 【发布时间】:2018-08-08 10:58:40 【问题描述】:

我是 Clojure 的初学者,在尝试阅读 Reducers 时,我发现了一个名为 foldable collection 的东西。

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

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

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

【问题讨论】:

技术答案是满足谓词#(satisfies? r/CollFold %) 的任何值。不幸的是,这不起作用,因为 r/CollFold 被扩展到 Object 并且任何值都是 Object ... 【参考方案1】:

答案在文档中,虽然不是很清楚:

此外,一些集合(持久向量和地图)是 折叠式。 reducer 上的 fold 操作执行减少 并行...

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

Reducer 位于 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 命名空间中,但 clojure.core.reducers 命名空间中没有 reduce。相反,clojure.core.reducers 中有一个名为 fold 的类似工作的函数。

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

因为折叠以非线性顺序访问数据(这对于链表来说非常低效),所以折叠只值得对像向量这样的随机访问数据结构进行)。


更新 #1

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

(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"

标准报告:

reduce   144 ms
r/fold    72 ms

更新 #2

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

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

【讨论】:

我明白什么是折叠,我的疑问是可折叠收藏是什么意思? hashmap 也是随机访问的数据结构吗? 折叠收藏有简单的定义吗?【参考方案2】:

Guy Steele 的这个演讲早于减速器,可能只是对他们的启发。 https://vimeo.com/6624203

【讨论】:

以上是关于Clojure 中的可折叠集合是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Clojure 中的可插拔向量处理单元

通过 Clojure 中的集合进行递归的惯用方式

在 Clojure 项目中存储项目版本号的常见约定是啥?

在 Clojure 中执行用户身份验证和授权的首选方式是啥?

“foo = bar || baz”的惯用 Clojure 是啥?

你用 Clojure 做 GAE 应用程序的方法是啥?