Are there any difference between these 2 functions in scheme?I am using Dr Racket R5RS language to make a simulator game and I could not decide which one is better.
问题:
回答1:
for-each
evaluates the given function on the list elements left-to-right, and discards the return value of the function. It's ideal for doing side-effecting things to each element of the list.
map
evaluates the given function on the list elements in no specific order (though most implementations will use either right-to-left or left-to-right), and saves the return value of the function to return to the caller. It's ideal for doing pure-functional processing on each element of the list.
If the return value of map
is not going to get used, it is better to use for-each
instead. That way, it doesn't have to bother collecting the return values from the function calls.
(Aside: in Clojure, the return value of map
is a lazy sequence, which means the given function is only invoked for the elements being materialised.)
Technical implementation details. A simplified one-list version of for-each
is usually implemented like this:
(define (for-each func lst)
(let loop ((rest lst))
(unless (null? rest)
(func (car rest))
(loop (cdr rest)))))
Really straightforward, and guarantees left-to-right order. Contrast with a simplified one-list version of map
:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
In Scheme, the evaluation order for function arguments is not specified. So for an expression like (foo (bar) (baz) (qux))
, the calls to bar
, baz
, and qux
can occur in any order, but they will all complete before foo
is called.
In this case, the (func (car rest))
can happen first, or it may happen after (recur (cdr rest))
. It's not guaranteed either way. This is why people say that map
does not guarantee an evaluation order.
回答2:
There is a big difference: map
returns the list containing the results of applying the given procedure on the elements of the list (or lists), while for-each
returns void.
> (for-each (λ (x) (add1 x)) '(1 2 3))
> (map (λ (x) (add1 x)) '(1 2 3))
'(2 3 4)
You use map
whenever you need the result of the computation and you use for-each
when you're interested in the side effects of that procedure.
The second important difference is that for-each
guarantees you that the given procedure is applied on the elements in order. For map
, although the list returned respects the order of the original list[s], it is not guaranteed that the calls were made in order.
more here