【发布时间】:2015-12-17 15:39:21
【问题描述】:
所以我的任务是在 Scheme 中使用 fold-left 或 fold-right 实现最基本版本的 'map' 函数和 'filter' 函数。我很难理解这些功能到底在做什么。这是我所拥有的:
(define (myMap f l)
(fold-left (lambda (f a) (f a)) '() l))
(define (myFilter f l)
(fold-left f '() l))
底部是我直觉认为应该的。应用过滤器(比如 number? 到 l 的每个元素并将结果放入空列表中)。顶部是完全错误的,但我觉得那更在正确的轨道上。使用某种 lambda 函数将函数应用于数字?
这是我正在寻找的输出示例:
(myMap sqrt '(4 9 16 25)) ; (2 3 4 5)
(myFilter odd? '(1 2 3 4 5)) ; (1 3 5)
【问题讨论】:
-
这里的诀窍是,与
map和filter不同,fold不一定返回一个列表。 fold 操作比 map 和 filter 更通用(正如可以根据 fold 定义它们的事实所证明的那样)。例如,通过使用折叠将列表(“reduce”是折叠的常见替代名称)减少为总和,可能更容易理解折叠的作用。试试(fold-left + 0 '(1 2 3 4 5))看看我的意思。 -
@AlexisKing 这是我在很多文档中找到的示例。我知道它像
(... (+ (+ (+ 0 1) 2) 3) ...)一样应用它,但我如何扩展它以使用任意函数做某事?我猜像(lambda (f l n) (append (f n) l))这样我可以将我应用函数的元素添加回列表?或者这没有意义 -
不,问题是提供给
fold的过程的元素不是列表。您不能在非列表中调用append。为了让fold返回一个列表,您的累加器函数必须明确执行在累加的每一步中建立一个新列表的职责。不过,这就是折叠:它是一种函数式操作,它封装了遍历列表并将每个值复合到“累加器”值的想法。累加函数接收当前累加器和新值,并产生一个新的累加器。 -
@amza 不,就像
(... (+ 3 (+ 2 (+ 1 0))) ...),用于左侧折叠。不是每个+都是可交换的(a+b == b+a 但 a-b != b-a)。 -
虽然和你的问题没有直接关系,但我前段时间深入写过左右折叠:codereview.stackexchange.com/a/87626/216。它甚至包括一个非常类似于
map和filter的东西的实现。
标签: functional-programming scheme fold