2014-12-15 18 views
3

Есть ли разница между этими двумя функциями в схеме? Я использую Dr Racket R5RS для создания симуляторной игры, и я не мог решить, какой из них лучше.For-each и map in Scheme

ответ

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

+0

В схеме без ракеты есть ли побочные эффекты? Что делает «для каждого» в MIT-Scheme? – SeanLetendre

+0

@SeanLetendre Как я понимаю, явная точка 'for-each' - это побочные эффекты, поэтому заказ гарантирован. Это то же самое во всех схемах. –

4

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 не гарантирует порядок оценки.