自定义地图功能 - 它是如何工作的?

时间:2014-02-23 23:18:44

标签: recursion scheme variadic-functions map-function

我为不明确的主题标题道歉。

我在Scheme中有这个函数,它是map函数的自定义实现。它工作正常,但我迷失了,试图理解它。

(define (my-map proc . ls)
  (letrec ((iter (lambda (proc ls0)
                   (if (null? ls0)
                       '()
                       (cons (proc (car ls0)) 
                             (iter proc (cdr ls0))))))
           (map-rec (lambda (proc ls0)
                     (if (memq '() ls0)
                         '()
                         (cons (apply proc (iter car ls0)) 
                               (map-rec proc (iter cdr ls0)))))))
    (map-rec proc ls)))

问题出在cons (proc (car ls0))。如果我是正确的,将(1 2 3) (4 5 6)传递给ls参数时,其实际值将为((1 2 3) (4 5 6))。因此,iter car ls0中的map-rec会将(1 2 3)传递给iter。因此,proc (car ls0)中的iter将采用(car (car (1 2 3)))形式,但这是不可能的,对吗?

我知道我的想法在某处有缺陷,但我无法弄清楚在哪里。

1 个答案:

答案 0 :(得分:1)

这是理解程序的一种方法:

  • iter帮助器与map相同,但在单个列表中运行。
  • map-rec帮助器推广iter,用于列表列表,当至少一个列表为空时停止
  • 这部分:(apply proc (iter car ls0))在每个列表的第一个元素上应用该过程;对iter的调用会创建列表car部分的列表
  • 这一部分:(map-rec proc (iter cdr ls0))同时推进所有列表的递归;对iter的调用会创建列表cdr部分的列表

也许重命名程序会使事情变得清晰。这是一个完全等效的实现,明确指出map-one在单个列表上运行而map-many在列表列表上运行这一事实:

(define (map-one proc lst)  ; previously known as `iter`
  (if (null? lst)
      '()
      (cons (proc (car lst))
            (map-one proc (cdr lst)))))

(define (map-many proc lst) ; previously known as `map-rec`
  (if (memq '() lst)
      '()
      (cons (apply proc (map-one car lst))
            (map-many proc (map-one cdr lst)))))

(define (my-map proc . lst) ; variadic version of `map-many`
  (map-many proc lst))

它的工作原理与原始my-map

相同
(my-map + '(1 2 3) '(4 5 6) '(7 8 9))
=> '(12 15 18)

您可以检查map-one是否真的是map,该列表适用于单个列表:

(map-one (lambda (x) (* x x))
         '(1 2 3 4 5))
=> '(1 4 9 16 25)

查看(map-one car lst)对列表列表的影响:

(map-one car '((1 4 5) (2 6 7) (3 8 9)))
=> '(1 2 3)

同样,请查看(map-one cdr lst)的工作原理:

(map-one cdr '((1 4 5) (2 6 7) (3 8 9)))
=> '((4 5) (6 7) (8 9))