我试图在方案中将两个x坐标和y坐标列表组合成对,我很接近,但无法获得返回的对列表。 以下内容可以使用嵌套循环匹配所有对,但我不确定将它们放到最佳方式,现在我只是将它们显示到控制台。
(define X (list 1 2 3 4 5))
(define Y (list 6 7 8 9 10))
(define (map2d X Y)
(do ((a 0 (+ a 1))) ; Count a upwards from 0
((= a (length X) ) ) ; Stop when a = length of list
(do ((b 0 (+ b 1))) ; Count b upwards from 0
((= b (length Y) ) ) ; Stop when b = length of second list
(display (cons (list-ref X a) (list-ref Y b))) (newline)
))
)
(map2d X Y)
我希望有这个功能输出
((1 . 6) (1 . 7) (1 . 8) ... (2 . 6) (2 . 7) ... (5 . 10))
然后我将使用map将此列表提供给另一个成对的函数。
奖励积分如果你可以帮助我让它更加递归(不是纯粹的功能,对吗?),这是我第一次使用函数式编程而且递归并不容易把握。谢谢!
答案 0 :(得分:1)
使用do
并不是非常惯用。您可以尝试嵌套map
s,这更符合Scheme的精神 - 使用内置的高阶程序是可行的方法!
; this is required to flatten the list
(define (flatmap proc seq)
(fold-right append '() (map proc seq)))
(define (map2d X Y)
(flatmap
(lambda (i)
(map (lambda (j)
(cons i j))
Y))
X))
很遗憾你没有使用Racket,这会更好:
(define (map2d X Y)
(for*/list ([i X] [j Y])
(cons i j)))
答案 1 :(得分:1)
ÓscarLópez的解决方案是正确而优雅的,并使您能够以功能语言编程的“正确”方式。但是,既然你开始研究递归,我将提出一个简单的递归解决方案,没有高级函数:
(define (prepend-to-all value y)
(if (null? y)
'()
(cons (cons value (car y)) (prepend-to-all value (cdr y)))))
(define (map2d x y)
(if (null? x)
'()
(append (prepend-to-all (car x) y) (map2d (cdr x) y))))
函数map2d
在第一个列表中重复出现:如果它为空,则笛卡尔积为空;否则,它将收集通过将x
的第一个元素添加到y
的所有元素之前获得的所有对,并将所有对通过将其自身应用于x
的其余部分而获得y
的元素。
函数prepend-to-all
将生成从单个值value
和列表y
的所有元素构建的所有对。它在第二个参数列表上重复出现。当y
为空时,结果为空对列表,否则,它会与value
和y
的第一个元素构建一对,并在前置结果上“汇总”它value
的所有剩余元素y
。
当你掌握递归时,你可以通过学习尾递归来传递到下一步,其中对函数的调用不包含在其他一些“构建”形式中,但是是第一个递归的呼叫。这种形式的优点是编译器可以将其转换为(更多)更有效的迭代程序。以下是适用于您的问题的此技术示例:
(define (map2d x y)
(define (prepend-to-all value y pairs)
(if (null? y)
pairs
(prepend-to-all value (cdr y) (cons (cons value (car y)) pairs))))
(define (cross-product x y all-pairs)
(if (null? x)
(reverse all-pairs)
(cross-product (cdr x) y (prepend-to-all (car x) y all-pairs))))
(cross-product x y '()))
关键思想是使用新参数定义一个辅助函数,该参数在构建时“累积”结果。这个“累加器”在辅助函数的调用中用()初始化,将作为递归的终端情况返回。在这种情况下情况更复杂,因为有两个函数,但您可以研究新版本的prepend-to-all
以查看其工作原理。请注意,要以自然顺序返回所有对,请在cross-product
函数的末尾反转结果。如果您不需要此订单,则可以省略reverse
以使该功能更有效。