Clojure交换!不在let绑定中的map函数内部工作

时间:2013-03-11 06:18:27

标签: dictionary clojure swap let

我有两个序列用于比较,我需要在地图中保留比较结果,第一个序列中的数据用作键,第二个数据用作val。这是一个有效的示例代码

(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里面发生了什么让绑定?怎么会丢失?

2 个答案:

答案 0 :(得分:6)

map是从序列中生成延迟序列,而你需要的是为序列中的每个项做一些操作(即交换),因此你需要使用doseq

编辑:(更新为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操作执行其延迟操作。

我见过很多人尝试使用map来做这样的某些操作,map应该仅用于一个目的,即将序列映射到另一个序列而不进行任何副作用操作。

答案 1 :(得分:4)

正如Ankur所说,最好使用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。 Ankur的版本不等同于原版

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]