Clojure 交换!在 let 绑定中的 map 函数内不起作用
Posted
技术标签:
【中文标题】Clojure 交换!在 let 绑定中的 map 函数内不起作用【英文标题】:Clojure swap! not working inside a map function in let bindings 【发布时间】:2013-02-26 06:14:00 【问题描述】:我有两个要比较的序列,我需要将比较结果保存在映射中,第一个序列中的数据用作键,第二个序列中的数据用作 val。下面是可以工作的示例代码
(def myAtom (atom ))
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn @myAtom) ; ==> 3 3
但是,将上面的“相同”的东西放入一个 let 绑定后,它就不再起作用了
(let [ myAtom (atom )]
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn @myAtom)) ;;==> empty???
所以问题是,在 let 绑定中 myAtom 会发生什么?怎么不见了?
【问题讨论】:
如果没有“else”分支,你可以使用when
而不是if
。
【参考方案1】:
map
是从序列中生成惰性序列,而您需要对序列中的每个项目执行某些操作(即交换),因此您需要使用doseq
编辑:(更新为@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 应该只用于一个目的,即将一个序列映射到另一个序列而没有任何副作用操作。
【讨论】:
【参考方案2】:正如 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]
【讨论】:
感谢 mobyte 这很有帮助!以上是关于Clojure 交换!在 let 绑定中的 map 函数内不起作用的主要内容,如果未能解决你的问题,请参考以下文章
在没有嵌套 let 的情况下在 Clojure 中绑定多个相关变量
`let` 在 Clojure 中是如何实现的,它的开销是多少?