Clojure binding of dynamic var not working as expected

后端 未结 3 1354
一生所求
一生所求 2020-12-11 20:53

From what I understand, setting a new binding on a dynamic var affects all functions called within that binding, and all functions called from those functions.

Why d

相关标签:
3条回答
  • 2020-12-11 21:21

    Another solution is to use Python-style generator functions available via lazy-gen and yield 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})
    
    0 讨论(0)
  • 2020-12-11 21:33

    This is caused by lazyness - map returns a lazy sequence which is defined inside the binding but is evaluated outside. You need to force the evaluation from inside:

    (binding [*out-dir* "/home/dave"] 
      (doall (map #(str *out-dir* %) [1 2 3])))
    
    0 讨论(0)
  • 2020-12-11 21:33

    It's true that laziness and dynamic bindings can cause problems; however, abandoning laziness is not the only solution. If you wish to preserve laziness (or to use dynamic bindings with pmap), use bound-fn or 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)
    
    0 讨论(0)
提交回复
热议问题