反复绑定

时间:2018-01-25 03:02:45

标签: clojure thread-safety lazy-evaluation

(def ^:dynamic *d* 1)

(binding [*d* 2]
  (println *d*)
  (repeatedly 1 #(println *d*)))

输出:

2
1

为什么呢?为什么repeatedly内的函数会在binding之外看到动态变量的值?

顺便说一句,我检查了匿名函数内外的(.getId (java.lang.Thread/currentThread)):它是一样的。

1 个答案:

答案 0 :(得分:9)

repeatedly创建的延迟序列从表单返回,然后只有在通过REPL打印后才能实现,在绑定被“解开”之后,此时匿名函数正在进行调用。要看到这种情况,请尝试以下两种变体:

(binding [*d* 2]
  (println *d*)
  (let [x (repeatedly 1 #(println *d*))]
    (println (realized? x))
    x))

(binding [*d* 2]
  (println *d*)
  (doall (repeatedly 1 #(println *d*))))

第二种变化迫使序列完全实现,同时仍然在绑定范围内。

请注意,另一种强制解决问题的方法是使用bound-fn“捕获”绑定:

(binding [*d* 2]
  (println *d*)
  (repeatedly 1 (bound-fn [] (println *d*))))