我必须在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)...)
。这是一个令人讨厌的问题。有没有人有任何见解?
答案 0 :(得分:1)
这个问题比你想象的要复杂得多。特别是,生成任意范围列表的笛卡尔积需要更多的工作 - 您是否尝试过两个以上范围的程序?这引起了我的兴趣,这一次我只给出了一个完整的解决方案,只使用为解决方案定义的程序,对列表进行简单操作(cons
,car
,cdr
,append
),lambda
,apply
和map
。
首先,帮助程序从最简单到最难。我们需要一种方法来生成一系列数字。如果可用,请使用build-list
或for-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))