Своп на Clojure! не работает внутри функции map в привязках let
У меня есть две последовательности Для сравнения, и мне нужно сохранить результаты сравнения в карте, причем данные в первой последовательности служат ключами, а во второй-vals. Вот пример кода, который работает
(def myAtom (atom {}))
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn @myAtom) ; ==> {3 3}
Однако после помещения "той же" вещи выше в один пусть привязки, это больше не работает
(let [ myAtom (atom {})]
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn @myAtom)) ;;==> {} empty???
Итак, вопрос в том, что происходит с myAtom внутри let binding? Почему же он пропал?
2 ответа:
map
состоит в том, чтобы генерировать ленивую последовательность из последовательности, тогда как то, что вам нужно, - это сделать определенную операцию (т. е. поменять местами) для каждого элемента в последовательности, следовательно, вам нужно использоватьdoseq
EDIT: (обновлено как предложение par @mobyte)
(let [myAtom (atom {}) a [1 2 3] b [4 5 3]] (doseq [[x y] (map vector a b)] (if (== x y) (swap! myAtom assoc x y ))) (prn @myAtom))
Ваш первый пример работает, потому что вы выполнили каждое выражение в REPL, которое заставило операцию map выполнить свои ленивые операции.
Я видел, как многие люди пытаются использовать карту для выполнения определенных операций, таких как эта, карта должна использоваться только для одной цели, то есть отображения последовательности в другую последовательность без каких-либо побочных действий.
Как упоминал Анкур, лучше использовать
doseq
для императивных операций:(let [myAtom (atom {})] (doseq [[a b] (map vector [1 2 3] [4 5 3])] (when (== a b) (swap! myAtom assoc a b ))) (prn @myAtom))
Но вы можете принудительно оценить результат карты, используя
dorun
в вашей первоначальной версии:(let [ myAtom (atom {})] (dorun (map #(when (== %1 %2) (swap! myAtom assoc %1 %2 )) [1 2 3] [4 5 3])) (prn @myAtom))
P.S. версия Анкура не эквивалентна оригиналу
doseq
:(doseq [a [1 2 3] b [4 5 3]] (println [a b])) => [1 4] [1 5] [1 3] [2 4] [2 5] [2 3] [3 4] [3 5] [3 3]
map
:(dorun (map #(println [%1 %2]) [1 2 3] [4 5 3])) => [1 4] [2 5] [3 3]