这两个函数在方案中有什么区别吗?我使用Dr Racket R5RS语言进行模拟器游戏,我无法确定哪个更好。
答案 0 :(得分:5)
for-each
从左到右评估列表元素上的给定函数,并丢弃函数的返回值。它非常适合对列表中的每个元素进行副作用。
map
不按特定顺序评估列表元素上的给定函数(尽管大多数实现将使用从右到左或从左到右),并保存函数的返回值以返回给来电者。它是对列表中每个元素进行纯函数处理的理想选择。
如果不会使用map
的返回值,则最好使用for-each
。这样,它就不必费心从函数调用中收集返回值。
(旁白:在Clojure中,map
的返回值是一个惰性序列,这意味着只为正在实现的元素调用给定的函数。)
技术实施细节。 for-each
的简化单列表版本通常如下所示:
(define (for-each func lst)
(let loop ((rest lst))
(unless (null? rest)
(func (car rest))
(loop (cdr rest)))))
非常简单,并保证从左到右的顺序。与map
的简化单列表版本对比:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
在Scheme中,未指定函数参数的评估顺序。因此,对于(foo (bar) (baz) (qux))
这样的表达式,对bar
,baz
和qux
的调用可以按任何顺序进行,但它们都会在foo
之前完成调用。
在这种情况下,(func (car rest))
可以先发生,也可以发生在(recur (cdr rest))
之后。无论如何都无法保证。这就是人们说map
不能保证评估顺序的原因。
答案 1 :(得分:2)
有一个很大的区别:map
返回包含在列表(或列表)的元素上应用给定过程的结果的列表,而for-each
返回void。
> (for-each (λ (x) (add1 x)) '(1 2 3))
> (map (λ (x) (add1 x)) '(1 2 3))
'(2 3 4)
只要您需要计算结果,就可以使用map
,当您对该程序的副作用感兴趣时,可以使用for-each
。
第二个重要区别是for-each
保证给定的过程按顺序应用于元素。对于map
,尽管返回的列表遵循原始列表[s]的顺序,但不能保证调用是按顺序进行的。
更多here