方案 - 在 map 中使用 foldr 并使 foldr proc 使用 map 迭代中给出的当前元素

Scheme - using foldr inside map and making the foldr proc use the current element given from the map iteration

我正在尝试编写以下函数,它获取 2 个列表列表和 returns 这些列表的笛卡尔积。

这是我写的:

;; Signature: mix-rows(rows1 rows2)
;; Purpose: returns a list of rows of the cartesian product of both rows 
;; Type: [ List(Row) * List(Row) -> List(Row) ]
;; Tests:
;; (mix-rows (list '(10 11) '(20 21)) (list '('u 'v) '('p 'q)))
;; ==> ((10 11 'u 'v)
;;      (10 11 'p 'q)
;;      (20 21 'u 'v)
;;      (20 21 'p 'q))
(define mix-rows
  (lambda (rows1 rows2)
    (map (lambda (row1)
           (foldr (lambda (row2)
                  (append row1 row2))
                  '()
                rows2))
         rows1)))

出于某种原因,最后一个 lambda 无法识别从遍历 rows1 的函数映射中给出的 row1。

我希望最后一个 lambda 遍历 rows2 并将每个元素追加到 row1,在追加所有 rows2 元素后,row1 将更改为 rows1 中的下一个元素。

为什么 lambda 不能识别第 1 行?

谢谢。

首先,如果您只需要一个 cartesian-product 函数,您可以使用 racket/list 中的 cartesian-product

> (cartesian-product
   (list '(10 11) '(20 21))
   (list '('u 'v) '('p 'q)))
'(((10 11) ('u 'v)) ((10 11) ('p 'q)) ((20 21) ('u 'v)) ((20 21) ('p 'q)))

你的测试用例与这个略有不同,因为你的测试用例拼接了内部列表,而这个没有。但是,如果那是您所需要的,您可以使用 (map append* ...) 轻松修复它。 append* 函数将一个列表的列表向下一层展平。

> (define (mix-rows rows1 rows2)
    (map append* (cartesian-product rows1 rows2)))
> (mix-rows
   (list '(10 11) '(20 21))
   (list '('u 'v) '('p 'q)))
'((10 11 'u 'v) (10 11 'p 'q) (20 21 'u 'v) (20 21 'p 'q))

虽然如果你想从头开始设计,但你实现的问题是foldr需要一个函数(X Y -> Y),一个双参数函数,但是你给了它一个函数(Row -> Row),一个单参数函数。你可以解决这个问题,但据我所知,你根本不需要 foldr 。你可能也指的是 map

(define mix-rows
  (lambda (rows1 rows2)
    (map (lambda (row1)
           (map (lambda (row2)
                  (append row1 row2))
                rows2))
         rows1)))

尽管如此,您的测试用例仍未通过,生成

> (mix-rows
   (list '(10 11) '(20 21))
   (list '('u 'v) '('p 'q)))
'(((10 11 'u 'v) (10 11 'p 'q)) ((20 21 'u 'v) (20 21 'p 'q)))

要摆脱那层额外的嵌套列表,您可以使用 append* 将该列表的列表向下一层展平。

;; Signature: mix-rows(rows1 rows2)
;; Purpose: returns a list of rows of the cartesian product of both rows 
;; Type: [ List(Row) * List(Row) -> List(Row) ]
;; Tests:
;; (mix-rows (list '(10 11) '(20 21)) (list '('u 'v) '('p 'q)))
;; ==> ((10 11 'u 'v)
;;      (10 11 'p 'q)
;;      (20 21 'u 'v)
;;      (20 21 'p 'q))
(define mix-rows
  (lambda (rows1 rows2)
    (append*
     (map (lambda (row1)
            (map (lambda (row2)
                   (append row1 row2))
                 rows2))
          rows1))))

但是,如果你想要一个真正的笛卡尔积,不拼接行,你可以通过将(append row1 row2)更改为(list row1 row2)来解决它。

(define mix-rows
  (lambda (rows1 rows2)
    (append*
     (map (lambda (row1)
            (map (lambda (row2)
                   (list row1 row2))
                 rows2))
          rows1))))

然后它匹配 cartesian-product 所做的。