如何使用foldr
和foldl
定义一个函数来反转Scheme中的列表?
我们想要的是使用foldl
调用以及使用foldr
调用的不同解决方案来反转Scheme中的列表的简洁解决方案,如下所示:
(define (foldl operation lst initial)
(if (null? lst) initial
(foldl operation
(cdr lst)
(operation (car lst) initial))))
和
(define (foldr operation lst initial)
(if (null? lst) initial
(operation
(car lst)
(foldr operation (cdr lst) initial))))
精明的人会观察到foldl
实现是尾递归的,因为返回的值是在调用每个递归步骤时计算的 - 在最后一步,整个答案已经计算完毕并简单地返回链。
foldr
实现不是尾递归的,因为它必须使用在递归链上传回的值来构建返回值。
因此,我们感兴趣的两个Scheme实现应该采用以下形式,
(define (rev1 lst)
(foldl ___________________________
**Solution:**
(define (rev1 lst)
(foldl cons lst '()))
和
(define (rev2 lst)
(foldr ___________________________
**Solution 1:**
(define (rev2 lst)
(foldr
(lambda (element accumulator)
(foldr cons accumulator (cons element '())))
lst '()))
**Solution 2:**
(define (rev2 lst)
(foldr
(lambda (element accumulator)
(append accumulator (cons element '())))
lst '()))
最终目标是能够调用以下内容,
(rev1 '(1 2 3)) -> (3 2 1)
(rev2 '(1 2 3)) -> (3 2 1)
foldl
解决方案应该相对简单(基于我们的直觉),但foldr
解决方案可能需要更多考虑。
之前的问题与此问题类似(但文档记载较少)最终未得到答复和/或已关闭。
答案 0 :(得分:2)
这看起来像家庭作业,所以我会给你一些提示,让你开始。 foldl
案例是微不足道的,你只需要发现正确的函数来传递,并记住:foldl
可以被视为向后处理列表(最后一个元素,最后一个元素),所以你必须做的是将列表中的当前元素与累计值粘在一起:
(define (rev1 lst)
(foldl <???> lst '()))
foldr
案例稍微困难一点,只需记住foldr
处理列表中的元素的顺序与输入列表中显示的顺序相同。同样,你必须找到正确的程序来调用:
(define (rev2 lst)
(foldr (lambda (e a)
<???>)
lst
'()))
您需要以某种方式将e
(当前元素)放在a
的 end ,即累计值。提示:您会发现append
和list
在这里很有用。
答案 1 :(得分:0)
您的rev1
'解决方案'无法编译...如果您将list
替换为l
> (define (rev1 l)
(foldl cons l '()))
> (rev1 '(1 2 3))
(3 2 1)
对于你的rev2
,这可以作为正文:
> (foldr (lambda (a b) (append b (list a))) '(1 2 3) '())
(3 2 1)