Что происходит, так это то, что переменная i захвачена, и функции возвращают значение, к которому она привязана, во время ее вызова. На функциональных языках такого рода ситуация никогда не возникает, так как я бы не вернулся. Однако, с python, а также, как вы видели с lisp, это больше не так.
Разница в вашем примере схемы заключается в семантике цикла do. Схема эффективно создает новую переменную i каждый раз в цикле, а не повторно использует существующую привязку i, как в других языках. Если вы используете другую переменную, созданную вне цикла, и измените ее, вы увидите то же поведение в схеме. Попробуйте заменить ваш цикл на:
(let ((ii 1)) (
(do ((i 1 (+ 1 i)))
((>= i 4))
(set! flist
(cons (lambda (x) (* ii x)) flist))
(set! ii i))
))
Посмотрите здесь для дальнейшего обсуждения этого вопроса.
[Edit] Возможно, лучший способ описать его - думать о цикле do как о макросе, который выполняет следующие шаги:
- Определить лямбду, принимающую один параметр (i), с телом, определяемым телом цикла,
- Немедленный вызов этой лямбды с соответствующими значениями i в качестве ее параметра.
т. эквивалент приведенного ниже питона:
flist = []
def loop_body(i): # extract body of the for loop to function
def func(x): return x*i
flist.append(func)
map(loop_body, xrange(3)) # for i in xrange(3): body
i больше не тот из родительской области видимости, а совершенно новая переменная в своей области (т. Е. Параметр лямбда-выражения), и поэтому вы получаете поведение, которое вы наблюдаете. В Python нет этой неявной новой области видимости, поэтому тело цикла for просто использует переменную i.