首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure clojure.core.reducers/fold和Scala fold有什么区别?

Clojure clojure.core.reducers/fold和Scala fold有什么区别?
EN

Stack Overflow用户
提问于 2018-08-31 06:50:03
回答 2查看 342关注 0票数 2

我偶然发现Clojure有clojure.core.reducers/fold函数。

另外,Scala有内置的fold函数,但不能理解它们的工作方式是否不同?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-31 08:19:57

我假设你说的是clojure.core.reducers/fold

Scala在sequences上的默认fold实现非常简单:

代码语言:javascript
复制
collection.fold(identityElem)(binOp)

简单地从identityElem开始,然后顺序地遍历集合,并将二元运算binOp应用于已经累积的结果和当前序列值,例如

代码语言:javascript
复制
(1 to 3).fold(42000)(_ + _)

将导致42000 + 1 + 2 + 3 = 42006

带完整签名的Clojure的fold

代码语言:javascript
复制
(r/fold n combinef reducef coll)

来自上面提到的包在两个阶段并行工作。首先,它将输入拆分成大小为n的较小组(大约),然后使用reducef减少每个组,最后使用combinef合并每个组的结果。

主要区别在于,combinef应该同时是零值二进制文件(Clojure具有多值函数),并且(combinef) (没有参数)将被调用来为每个分区生成标识元素(因此,this documentation是正确的,而this documentation是错误的)。

也就是说,为了从上面的例子中模拟Scala的折叠,必须编写类似这样的代码:

代码语言:javascript
复制
(require '[clojure.core.reducers :as r])

(r/fold 3 (fn ([] 42000) ([x y] y)) + [1 2 3])

总的来说,Scala的fold

代码语言:javascript
复制
collection.fold(identityElement)(binOp)

reducers/fold可以按如下方式进行模拟:

代码语言:javascript
复制
(r/fold collectionSize (fn ([] identityElem) ([x y] y)) binOp collection)

(请注意,([x y] y)的巧妙设计去掉了第一个参数,这是故意的)。

我猜这个接口并不打算用于任何非么半群的零二进制操作,这就是为什么Scala的fold很难用Clojure的fold来模拟的原因。如果你想要一些像Scala的fold那样的东西,可以在Clojure中使用reduce

编辑

哦,等等。文档实际上说明了

组合函数必须是关联的,并且在不带参数的情况下调用时,(组合函数)必须生成其标识元素

也就是说,我们实际上被迫使用monoid作为combinef,所以上面的42000, ([x y] y)-example实际上是无效的,并且行为实际上是未定义的。从严格的技术意义上讲,我以某种方式获取42006的事实是一个技巧,它依赖于库函数的未定义行为来获得所需的结果42006

考虑到这些额外的信息,我根本不确定Scala的fold能否被Clojure的core.reducers/fold模拟。Clojure的fold似乎被限制为使用monoid进行缩减,而Scala的折叠更接近于一般的List折叠,代价是并行性。

票数 2
EN

Stack Overflow用户

发布于 2018-08-31 06:55:18

clojure.core.reducers命名空间是专为并行处理大型数据集而设计的实现。你可以在这里找到完整的文档:

https://clojure.org/reference/reducers

代码语言:javascript
复制
(r/fold reducef coll)
(r/fold combinef reducef coll)
(r/fold n combinef reducef coll)

r/fold接受一个可简化的集合,并将其划分为大约n个元素(默认为512个)的组。使用reducef函数对每个组进行缩减。在不带任何参数的情况下调用reducef函数,以在每个分区中生成一个标识值。然后使用combinef (缺省为reducef)函数对这些缩减的结果进行缩减。在不带参数的情况下调用时,(combinef)必须生成它的标识元素-这将被多次调用。操作可以并行执行。结果将保持秩序。

在你的机器达到极限之前,你应该坚持使用基本的reduce函数:

https://clojuredocs.org/clojure.core/reduce

这在本质上与Scala的fold函数相同:

代码语言:javascript
复制
(reduce + 0 [1 2 3 4 5]) => 15

其中函数签名为:

代码语言:javascript
复制
(reduce <op> <init-val> <collection-to-be-reduced> )
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52106357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档