在 Racket 中寻找关于 'map' 的说明

Looking for clarification on 'map' in Racket

Whosebug 的新手和球拍的新手。我一直在使用此文档研究球拍:https://docs.racket-lang.org/reference/pairs.html

这是我对地图的理解:

(map (lambda (number) (+ 1 number))'(1 2 3 4))

这会将 '(1 2 3 4) 分配给变量 number ,然后 map 执行 (+ 1 '(1 2 3 4)).

但是当我看到类似的东西时:

(define (matrix_addition matrix_a matrix_b)
  (map (lambda (x y) (map + x y)) matrix_a matrix_b))

我迷路了。我假设我们正在分配两个变量 xy,然后执行 (map + x y),但我不明白 (map + x y) 是什么或如何工作。

我遇到的另一个问题是

(define (matrix_transpose matrix_a)
  (apply map (lambda x x) matrix_a))

(lambda x x) 到底是做什么的?

非常感谢您的澄清。如您所见,我一直在按照我朋友的建议进行矩阵运算。

this assigns '(1 2 3 4) to variable number ,then map performs (+ 1 '(1 2 3 4)).

不,这不是它的作用。 map是一个循环函数,它为列表中的每个元素分别调用函数,returns一个结果列表。

所以首先它将number绑定到1并执行(+ 1 number),即(+ 1 1)。然后它绑定number2并执行(+ 1 number),即(+ 1 2)。等等。所有的结果都收集到一个列表中,所以它 returns (2 3 4 5).

进入矩阵运算,矩阵表示为列表的列表,因此我们需要嵌套循环,这是使用对 map.

的嵌套调用完成的
(map (lambda (x y) (map + x y)) matrix_a matrix_b)

外层map的工作原理如下:首先将xy分别绑定到matrix_amatrix_b的第一个元素,然后执行(map + x y)。然后将xy绑定到matrix_amatrix_b的第二个元素上,并执行(map + x y)。对于两个列表的每个元素,依此类推。最后它 returns 所有这些结果的列表。

里面的(map + x y)把两个列表对应的元素相加,返回求和的列表。例如。 (map + '(1 2 3) '(4 5 6)) returns (5 7 9).

所以所有这些一起创建了一个列表列表,其中每个元素都是 matrix_amatrix_b.

对应元素的总和

最后,

what does (lambda x x) exactly do?

它将 x 绑定到所有参数的列表,并且 returns 该列表。所以 ((lambda x x) 1 2 3 4) returns 列表 (1 2 3 4)。它基本上是 apply 的反函数,它将一个列表扩展到一个函数的多个参数中。

(apply (lambda x x) some-list)

returns some-list.

的副本

这是一种思考 map 的方法:

(map f (list 1 2 3)) 
; computes 
(list (f 1) (f 2) (f 3))

(map f (list 1 2 3) (list 11 22 33)) 
; computes 
(list (f 1 11) (f 2 22) (f 3 33))

所以您的 + 示例变为:

(map + (list 1 2 3) (list 11 22 33)) 
; computes 
(list (+ 1 11) (+ 2 22) (+ 3 33))

也就是 (list 12 24 36).

开头写的比较清楚

(define f (lambda (x y) (+ x y)))
(map f (list 1 2 3) (list 11 22 33)))

但是当你习惯了maplambda之后,shorthand

(map (lambda (x y) (+ x y)) (list 1 2 3) (list 11 22 33)))

有用。

this assigns '(1 2 3 4) to variable number ,then map performs (+ 1 '(1 2 3 4)).

如果就这么简单,为什么需要 map。你可以直接做 (+ 1 '(1 2 3 4)) 。这是 map1 的一种实现,即 map 只能有一个列表参数:

(define (map1 fn lst)
  (if (empty? lst)
      empty
      (cons (fn (first lst))
            (map1 f (rest lst)))))

它的作用:

(map1 add1 '(1 2 3))
; ==> (cons (add1 1) (cons (add1 2) (cons (add1 3) empty)))
; same as (list (add1 1) (add1 2) (add1 3))

真正的 map 接受任意数量的列表参数,然后期望元素函数采用与列表参数一样多的元素。例如

(map (lambda (l n s) (list l n s)) '(a b c) '(1 2 3) '($ % *))
; ==> ((a 1 $) (b 2 %) (c 3 *))

在不知道元素数量的情况下执行此操作的一种非常酷的方法是 unzip

(define (unzip . lst)
  (apply map list lst))

(unzip '(a b c) '(1 2 3) '($ % *))
; ==> ((a 1 $) (b 2 %) (c 3 *))

所以 apply 将对 (map list '(a b c) '(1 2 3) '($ % *)) 的调用展平,而 list 接受任意元素,因此它最终的工作方式与上一个示例相同,但它也适用于其他维度:

(unzip '(a b c d) '(1 2 3 4))
; ==> ((a 1) (b 2) (c 3) (d 4))

map的第一个参数是一个函数。此函数可能需要一个或多个参数。参数列表中的函数后面是一个或多个列表。

map 从列表的第一个元素到最后一个元素并行循环。 因此将每个列表的第 i 个位置作为函数的参数 并将结果收集到结果列表中 returns.

现在三个简短的例子可以让你清楚地图是如何遍历列表的:

(map list '(1 2 3)) 
;; => '((1) (2) (3))

(map list '(1 2 3) '(a b c)) 
;; => '((1 a) (2 b) (3 c))

(map list '(1 2 3) '(a b c) '(A B C))
;; => '((1 a A) (2 b B) (3 c C))