Почему map-each сохраняет последнее значение для ссылок на устанавливаемое слово?

map-each можно использовать для оценки некоторого кода для каждого члена в коллекции и агрегирования результатов оценки в блоке:

>> values: map-each x [1 2] [
    print ["Doing mapping for" x]
    x * 10
   ]
Doing mapping for 1
Doing mapping for 2
== [10 20]

Таким образом я строил блок из блоков. Но я забыл, что, поскольку блоки не оцениваются по умолчанию, x останется как есть и не получит желаемое значение:

>> blocks: map-each x [1 2] [
    print ["Doing mapping for" x]
    [x * 10]
   ]
Doing mapping for 1
Doing mapping for 2
== [[x * 10] [x * 10]]

В этом нет ничего удивительного. После оценки x не имеет значения - не говоря уже о возможности принимать многие значения:

>> probe x
** Script error: x has no value

Так что уже слишком поздно, оценка должна выполняться с помощью REDUCE или COMPOSE внутри тела карты-each. Но...

>> reduce first blocks
== [20]

>> reduce second blocks
== [20]

Оценки элементов в блоке результатов не вызывают ошибки, а ведут себя так, как если бы x имел значение последней итерации.

Как он это делает? Должен ли он делать это?


person HostileFork says dont trust SE    schedule 15.05.2014    source источник
comment
Похоже, что блок все еще привязан к анонимному контексту, создаваемому map-each, и поэтому x сохраняет свое последнее значение.   -  person Graham Chiu    schedule 15.05.2014


Ответы (2)


Так же, как FOREACH, MAP-EACH связывает блок, который вы ему даете, в контексте, который он создает, и выполняет его там.

X никогда не создается глобально. тот факт, что вы дали ему слово (а не световое слово) в качестве аргумента, управляется интерфейсом функции, который, вероятно, использует обозначение светового слова и использует слово данное, как есть, без оценки, вместо значение, которое он может содержать.

по этой причине X, используемый в вашем вызове для сопоставления, не запускает

** Script error: x has no value

поскольку map-each захватывает его до того, как оно будет оценено, и напрямую использует слово только как токен.

Чтобы проиллюстрировать, как связывание работает более наглядно, и показать, как 'X может выжить за пределами своего исходного контекста, вот пример, который иллюстрирует основу того, как слова связаны в Rebol (и тот факт, что эта привязка сохраняется).

посмотрите на этот пример:

a: context [x: "this"]  
b: context [x: "is"]  
c: context [x: "sensational!"]

>> blk: reduce [in a 'x   in b 'x   in c 'x]
== [x x x]

x: "doh!"
== "doh!"

>> probe reduce blk
["this" "is" "sensational!"]

Мы создали единый блок с тремя 'X словами, но ни одно из них не привязано к одному и тому же контексту.

Поскольку привязка в Rebol статична, а область видимости не существует, одно и то же слово может иметь разные значения, даже когда они обрабатываются в одном контексте (в этом случае консоль является глобальным контекстом пользователя).

Это предпоследний пример того, почему слово на самом деле НЕ является переменной в Rebol.

person moliad    schedule 22.05.2014
comment
примечание: мой ответ немного больше, чем исходный вопрос, но он дает немного больше информации о том, как Rebol работает внутри, что может быть более полезно для новичков. - person moliad; 22.05.2014

blocks: map-each x [1 2] [
    print ["Doing mapping for" x]
    [x * 10]
]

probe bound? first blocks/1

дает это

Doing mapping for 1
Doing mapping for 2
make object! [
    x: 2
]
person Graham Chiu    schedule 15.05.2014