【问题标题】:Clojure binding of dynamic var not working as expected动态 var 的 Clojure 绑定未按预期工作
【发布时间】:2015-11-03 13:23:57
【问题描述】:

据我了解,在动态 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")

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这是由惰性引起的 - map 返回一个惰性序列,该序列在绑定内部定义但在外部评估。您需要从内部强制评估:

    (binding [*out-dir* "/home/dave"] 
      (doall (map #(str *out-dir* %) [1 2 3])))
    

    【讨论】:

    • 啊,就是这样。能够在此处找到有关绑定陷阱的更多深入信息:link
    • @DavidVail,请注意,自从那篇博文撰写以来,情况已经有所改善(仅仅一个月后,Clojure 1.1 引入了bound-fn)。
    【解决方案2】:

    懒惰和动态绑定确实会导致问题;然而,摒弃懒惰并不是唯一的解决办法。如果您希望保持惰性(或使用pmap 的动态绑定),请使用bound-fnbound-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)
    

    【讨论】:

      【解决方案3】:

      另一种解决方案是使用 Python 样式的生成器函数,可通过 lazy-genyield from the Tupelo library 获得:

      (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})
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-19
        • 2012-08-17
        • 2018-03-09
        • 2011-08-28
        • 2019-04-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多