使用foldl和foldr反转Scheme中的列表

时间:2013-11-05 01:28:16

标签: list scheme reverse fold

如何使用foldrfoldl定义一个函数来反转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解决方案可能需要更多考虑。

之前的问题与此问题类似(但文档记载较少)最终未得到答复和/或已关闭。

2 个答案:

答案 0 :(得分:2)

这看起来像家庭作业,所以我会给你一些提示,让你开始。 foldl案例是微不足道的,你只需要发现正确的函数来传递,并记住:foldl可以被视为向后处理列表(最后一个元素,最后一个元素),所以你必须做的是将列表中的当前元素与累计值粘在一起:

(define (rev1 lst)
  (foldl <???> lst '()))

foldr案例稍微困难一点,只需记住foldr处理列表中的元素的顺序与输入列表中显示的顺序相同。同样,你必须找到正确的程序来调用:

(define (rev2 lst)
  (foldr (lambda (e a)
           <???>)
         lst
         '()))

您需要以某种方式将e(当前元素)放在a end ,即累计值。提示:您会发现appendlist在这里很有用。

答案 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)