Scheme中的变量函数(使用嵌套映射)

时间:2012-10-22 10:30:14

标签: maps scheme

我必须在Scheme中定义一个可变参数函数,它采用以下形式:(define (n-loop procedure [a list of pairs (x,y)])其中对的列表可以是任意长度。

每对指定较低(包含)和上限(不包括)。也就是说,以下函数调用:(n-loop (lambda (x y) (inspect (list x y))) (0 2) (0 3))产生:

(list x y) is (0 0)
(list x y) is (0 1)
(list x y) is (0 2)
(list x y) is (1 0)
(list x y) is (1 1)
(list x y) is (1 2)

现在,我之前已经发布过这个主题并且得到了很好的帮助。但是,我已经获得了新的指导方针。只能使用嵌套映射找到解决方案。

我一直在讨论的方法如下:找到第一组边界指定的所有值(在示例中为(0 1 2))。这可以通过名为(enumerate lowBound highBound)的函数来完成。然后,我需要获取每个数字,并在下一组边界(0 1 2 3)中使用每个数字,得到((0 0) (0 1) (0 2) (0 3) (1 0)...)

我在这一点上所写的内容如下:

(define (n-loop op . pairs)
     (apply op (generate pairs))
)

(define (generate pairs)
    (map (lambda (x) (cons x (generate (cdr pairs)))) 
         (map (lambda (x) (enumerate (car x) (cadr x))) pairs))
)

但对于给定的数字,当我需要(0 1 0 1 2 0 1 2 0 1 2)时,这会输出((0 0) (0 1) (0 2) (0 3) (1 0)...)。这是一个令人讨厌的问题。有没有人有任何见解?

1 个答案:

答案 0 :(得分:1)

这个问题比你想象的要复杂得多。特别是,生成任意范围列表的笛卡尔积需要更多的工作 - 您是否尝试过两个以上范围的程序?这引起了我的兴趣,这一次我只给出了一个完整的解决方案,只使用为解决方案定义的程序,对列表进行简单操作(conscarcdrappend),lambdaapplymap

首先,帮助程序从最简单到最难。我们需要一种方法来生成一系列数字。如果可用,请使用build-listfor-list,但如果您需要从头开始实施,请执行此操作:

(define (enumerate low high)
  (if (>= low high)
      '()
      (cons low
            (enumerate (add1 low) high))))

现在我们需要一种折叠(减少,累积)列表中值的机制。如果可用,请使用foldr,否则请按照以下方式实施:

(define (reduce proc lst init)
  (if (null? lst)
      init
      (proc (car lst)
            (reduce proc (cdr lst) init))))

为了避免在列表中进行不必要的嵌套,请使用flatmap - 一个映射和展平值列表的过程:

(define (flatmap proc lst)
  (reduce (lambda (e acc)
            (append (proc e) acc))
          lst '()))

这是解决方案的核心 - 一个生成任意长的值列表的笛卡尔积的过程,表示范围:

(define (product . args)
  (reduce (lambda (pool result)
            (flatmap (lambda (x)
                       (map (lambda (y)
                              (cons x y))
                            result))
                     pool))
          args
          '(())))

最后,问题中的程序。它使用上面定义的帮助程序,注意到收到的op可以有任意数量的参数(取决于指定的范围数),所以我们需要在每个生成的元组值上使用apply

(define (n-loop op . pairs)
  (map (lambda (tuple) (apply op tuple))
       (apply product
              (map (lambda (pair)
                     (enumerate (car pair) (cadr pair)))
                   pairs))))

像这样测试:

(n-loop (lambda (x y z) (list x y z))
        '(0 2) '(0 3) '(4 6))

> '((0 0 4) (0 0 5) (0 1 4) (0 1 5) (0 2 4) (0 2 5)
    (1 0 4) (1 0 5) (1 1 4) (1 1 5) (1 2 4) (1 2 5))