首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >学习计划,尝试推行地图

学习计划,尝试推行地图
EN

Stack Overflow用户
提问于 2014-05-10 16:16:50
回答 1查看 3.3K关注 0票数 1

我试图实现地图使用与折叠在计划。我引用了这个站点:ref1,这是我从第一个元素中理解折叠、=>左关联折叠(foldl)折叠/迭代的方式。(向前)右关联折叠(foldr)折叠/从最后一个元素迭代。(向后) Q1,我明白了吗?

来自ref1 : foldl,foldr的实现

代码语言:javascript
复制
 `1) foldl (left-associate fold)`
  (define (foldl func accum lst)
   (if (null? lst)
        accum
        (foldl func (func accum (car lst)) (cdr lst))))

2) foldr (right-associate fold)
 (define (foldr func end lst)
   (if (null? lst)
      end
      (func (car lst) (foldr func end (cdr lst)))))

=>用折叠实现映射,ref1也有带折叠代码的映射,就是这样。

代码语言:javascript
复制
1) map implementation using foldr from ref1.
  (define (map func lst)      
     (foldr (lambda (x y) (cons (func x) y)) '() lst))

**[Q2] map impelementation using foldl from myself** 
  (define (fold-map-left pr list)
    (foldl 
       (lambda (sublist element) (cons (pr element) sublist))
       '() 
       list)
  what I get as the output...
  e.g. (fold-map-left (lambda(n) (expt n n)) '(1 2 3 4)) 
       output => (256 27 4 1): backwards 
  • 我知道左关联折叠/向后迭代,所以首先要把最后一个折叠放到输出中.那么我能做什么使输出按正确的顺序进行呢?我的代码还有什么问题吗?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-10 17:06:01

首先,我认为您的foldl实现有点不正确,在Scheme中实现它的通常方法是(但是一定要阅读@JoshuaTaylor的评论以了解结果):

代码语言:javascript
复制
(define (foldl func accum lst)
  (if (null? lst)
      accum
      (foldl func
             (func (car lst) accum) ; here's the change
             (cdr lst))))

关于第一个问题:这两种折叠都从左到右使用输入列表,但它们在构建输出结果的方式上有所不同:foldl在开始时累加第一个输入元素,然后在结果的基础上累加第二个元素,依此类推;如果我们构建一个列表作为输出,那么第一个元素将是最后一个(并用这个示例测试您自己的foldl实现,以了解为什么我说它有点错):

代码语言:javascript
复制
(foldl cons '() '(1 2 3 4 5))
=> '(5 4 3 2 1)

另一方面,foldr递归地前进,直到到达空列表,然后,当递归开始展开时,最后一个元素首先被累积,然后在结果的顶部积累第二到最后的元素,等等,这样就保持了输入的相同顺序:

代码语言:javascript
复制
(foldr cons '() '(1 2 3 4 5))
=> '(1 2 3 4 5)

关于第二个问题:根据map实现foldr会更简单,因为正如我们之前看到的那样,它保留了输入顺序。这与您的相同,但具有更好的格式和变量名称:

代码语言:javascript
复制
(define (map func lst)
  (foldr (lambda (ele acc)
           (cons (func ele) acc))
         '()
         lst))

但是,当然,我们可以使用foldl并在结束时反转结果(或者:在将列表传递给foldl之前反转列表):

代码语言:javascript
复制
(define (map func lst)
  (reverse
   (foldl (lambda (ele acc)
            (cons (func ele) acc))
          '()
          lst)))

同时拥有foldlfoldr的想法是什么?这是一种权衡(请务必阅读@ChrisJester的评论,从性能的角度讨论实现方面的问题)。在构建输出时,foldr将保持与输入相同的顺序,但它将生成一个与输入大小成正比的递归过程:注意,func是在调用递归调用后执行的。

另一方面,foldl将以反向顺序构建输出,但它将生成一个在常量空间中运行的迭代过程:注意,在调用递归调用之后没有什么可做的了,因此它的尾递归和Scheme被优化以有效地处理这种递归。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23583425

复制
相关文章

相似问题

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