据我所知,在动态var上设置新绑定会影响该绑定中调用的所有函数,以及从这些函数调用的所有函数。
为什么绑定在下面的第一个例子中似乎丢失了?
(def ^:dynamic *out-dir* "/home/user")
(binding [*out-dir* "/home/dave"] (map #(str *out-dir* %) [1 2 3]))
; gives: ("/home/user1" "/home/user2" "/home/user3")
; expected: ("/home/dave1" "/home/dave2" "/home/dave3")
(binding [*out-dir* "/home/dave"] (conj (map #(str *out-dir* %) [1 2 3]) *out-dir*))
; gives: ("/home/dave" "/home/dave1" "/home/dave2" "/home/dave3")
答案 0 :(得分:5)
这是由懒惰引起的 - map
返回一个懒惰序列,该序列在绑定中定义但在外部进行评估。您需要从内部强制进行评估:
(binding [*out-dir* "/home/dave"]
(doall (map #(str *out-dir* %) [1 2 3])))
答案 1 :(得分:3)
懒惰和动态绑定确实会导致问题;然而,放弃懒惰不是唯一的解决方案。如果您希望保留懒惰(或使用pmap
动态绑定),请使用bound-fn
或bound-fn*
。
(def ^:dynamic x 0)
=> (binding [x 3] (map #(+ x %) (range 10)))
;; (0 1 2 3 4 5 6 7 8 9)
=> (binding [x 3] (map (bound-fn [y] (+ x y)) (range 10)))
;; (3 4 5 6 7 8 9 10 11 12)
=> (binding [x 3] (map (bound-fn* #(+ % x)) (range 10)))
;; (3 4 5 6 7 8 9 10 11 12)
答案 2 :(得分:0)
另一种解决方案是使用lazy-gen
和yield
from the Tupelo library提供的Python样式生成器函数:
(ns tst.demo.core
(:use demo.core tupelo.test)
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(def ^:dynamic foo 1)
(dotest
(let [result (binding [foo 3]
(lazy-gen
(doseq [x (range 3)]
(yield {:foo foo :x x})))) ]
(println result)))
result => ({:foo 3, :x 0}
{:foo 3, :x 1}
{:foo 3, :x 2})