Своп на 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 2

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]