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
, and qux
可以按任何顺序发生,但它们都会在之前完成foo
叫做。
在这种情况下,(func (car rest))
可以先发生,也可以在之后发生(recur (cdr rest))
。无论哪种方式都不能保证。这就是为什么人们说map
不保证评估顺序。