Есть ли разница между этими двумя функциями в схеме? Я использую Dr Racket R5RS для создания симуляторной игры, и я не мог решить, какой из них лучше.For-each и map in Scheme
ответ
Существует большая разница: 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
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))))))
В схеме, порядок вычисления аргументов функции не определен. Поэтому для выражения типа (foo (bar) (baz) (qux))
вызовы bar
, baz
и qux
могут происходить в любом порядке, но все они будут завершены до того, как вызывается foo
.
В этом случае сначала может произойти ошибка (func (car rest))
, или это может произойти после (recur (cdr rest))
. Это не гарантируется в любом случае. Вот почему люди говорят, что map
не гарантирует порядок оценки.
В схеме без ракеты есть ли побочные эффекты? Что делает «для каждого» в MIT-Scheme? – SeanLetendre
@SeanLetendre Как я понимаю, явная точка 'for-each' - это побочные эффекты, поэтому заказ гарантирован. Это то же самое во всех схемах. –