关于字典:方案 – 在 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 个列表并返回这些列表的笛卡尔积。

这是我写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
;; 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 不能识别 row1?

谢谢。


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

1
2
3
4
> (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* 函数将列表列表向下一层展平。

1
2
3
4
5
6
> (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 那里。

1
2
3
4
5
6
7
(define mix-rows
  (lambda (rows1 rows2)
    (map (lambda (row1)
           (map (lambda (row2)
                  (append row1 row2))
                rows2))
         rows1)))

虽然,这仍然使您的测试用例失败,产生

1
2
3
4
> (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* 将该列表列表向下展平一层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
;; 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) 来修复它。

1
2
3
4
5
6
7
8
(define mix-rows
  (lambda (rows1 rows2)
    (append*
     (map (lambda (row1)
            (map (lambda (row2)
                   (list row1 row2))
                 rows2))
          rows1))))

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