Search code examples
clojurelazy-evaluation

In Clojure, how would I redefine vars for a lazy sequence?


In a namespace, I have two dynamic vars:

(def ^:dynamic *form-data*)
(def ^:dynamic *form-errors*)

In order to quickly create new bindings for them, I've made a wrapper macros:

(defmacro with-form [data errors & body]
  `(binding [*form-data*    ~data 
             *form-errors*  ~errors]
     ~@body))

I have several functions in the same namespace that rely on those vars, one of them is input-field.

It works when I use the function by itself, in a repl. But when I use it this way:

(vf/with-form {} {}
  (map #(vf/input-field hf/text-field %) [:name :code]))

I get an error: Attempting to call unbound fn: *form-errors*

I guess the problem is that bindings runs map, creates a lazy seq, and unbounds the vars back to their original state. Is there a way around this limitation?

Thank you.


Solution

  • Use doall to force the entire lazy seq to be realised:

    (vf/with-form {} {}
      (doall (map #(vf/input-field hf/text-field %) [:name :code])))
    

    This example in the docs for binding illustrates the same technique.

    Alternatively, to retain laziness use bound-fn*, as demonstrated by this example in the docs:

    (vf/with-form {} {}
      (map (bound-fn* #(vf/input-field hf/text-field %)) [:name :code]))