For-each并在Scheme中映射

时间:2014-12-15 00:23:42

标签: map foreach scheme racket

这两个函数在方案中有什么区别吗?我使用Dr Racket R5RS语言进行模拟器游戏,我无法确定哪个更好。

2 个答案:

答案 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))这样的表达式,对barbazqux的调用可以按任何顺序进行,但它们都会在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