Fold (又名 reduce)被认为是非常重要的高阶功能。 Map 可以用 fold (看这里)。但这听起来比我实用。典型的用途可能是获取数字的总和,产品或最大数字,但是这些功能通常接受任何数量的参数。那为什么写 (fold + 0 '(2 3 5)) 什么时候 (+ 2 3 5) 工作正常。我的问题是,在哪种情况下,使用最容易或最自然 fold?

有帮助吗?

解决方案

重点 fold 是更抽象。这并不是说您可以做以前做不到的事情,而是您可以更轻松地做它们。

用一个 fold, ,您可以概括 任何 在两个元素上定义的函数适用于任意数量的元素。这是一场胜利,因为它通常比列表更容易编写,测试,维护和修改一个应用两个参数的单个函数。而且它总是更容易编写,测试,维护等。一个简单的功能,而不是具有相似但不符合功能的两个功能。

自从 fold (为此, map, filter, ,朋友)具有明确的行为,使用这些功能比显式递归更容易理解代码。

基本上,一旦拥有一个版本,您就可以免费获得另一个版本。最终,您最终做的工作更少以获得相同的结果。

其他提示

这里有一些简单的示例 reduce 效果很好。

找到每个子列表的最大值的总和

Clojure:

user=> (def x '((1 2 3) (4 5) (0 9 1)))
#'user/x
user=> (reduce #(+ %1 (apply max %2)) 0 x)
17

球拍:

> (define x '((1 2 3) (4 5) (0 9 1)))
> (foldl (lambda (a b) (+ b (apply max a))) 0 x)
17

从列表构建地图

Clojure:

user=> (def y '(("dog" "bark") ("cat" "meow") ("pig" "oink")))
#'user/y
user=> (def z (reduce #(assoc %1 (first %2) (second %2)) {} y))
#'user/z
user=> (z "pig")
"oink"

对于一个更复杂的Clojure示例 reduce, , 查看 我的解决方案 提出欧拉问题 18 & 67.

也可以看看: 减少申请

在共同的LISP函数中,不接受任何数量的参数。

每个常见的LISP实施中都有一个不变的定义 呼叫arguments-limit, ,必须是50或更大。

这意味着任何此类便携式书面功能都应至少接受50个参数。但这可能只有50。

存在此限制,以允许编译器可能使用优化的调用方案,并且不提供一般情况,如果可以通过无限数量的参数。

因此,要在便携式公共LISP代码中真正处理大型(大于50个元素)或向量,则有必要使用迭代构造,简化,映射和类似的方法。因此,也有必要不使用 (apply '+ large-list) 但是使用 (reduce '+ large-list).

  1. 你的例子 (+ 2 3 4)只能因为您事先知道参数的数量而起作用。折叠在列表上的大小可能会有所不同。

  2. fold/reduce 是“ cdr-down list”模式的一般版本。每个算法都涉及处理顺序的每个元素并从中计算一些返回值。它基本上是foreach循环的功能版本。

使用折叠的代码通常很尴尬。这就是为什么人们更喜欢地图,过滤器,存在,总和等等的原因。这些天,我主要是写编译器和口译员。这是我使用折叠的一些方法:

  • 计算功能,表达或类型的自由变量集
  • 将函数的参数添加到符号表中,例如,用于键入检查
  • 累积从一系列定义生成的所有明智错误消息的集合
  • 在启动时间将所有预定义的类添加到Smalltalk解释器

所有这些用途的共同点是,他们正在积累有关A的信息 序列 变成某种 或者 字典. 非常实用。

这是一个没有其他人提到的例子。

通过将功能与“折叠”(fold''这样的小定义的界面(例如“ fold”)),您可以替换该实现,而无需破坏使用程序的程序。例如,您可以做一个 在数千个PC上运行的分布式版本, ,因此使用它的分类算法将成为 分布式排序, , 等等。您的程序变成了 更健壮,更简单,更快.

您的例子是一个琐碎的例子: + 已经进行了许多参数,在很少的记忆中很快运行,并且已经由谁写成的编译器编写和调试。这些属性通常不需要我需要运行的算法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top