> Richard--- > It's not the same thing: > > (class (doall (map (fn [x] x) [1 2 3]))) > -> clojure.lang.LazySeq > > whereas > > (class (binding [*strict* true] > (map (fn[x] x) [1 2 3]))) > -> clojure.lang.LazilyPersistentVector
From Clojure's perspective those *are* the same thing: user=> (= (map identity [1 2 3]) [1 2 3]) true Also, just because it's lazy doesn't mean it hasn't already done the work, and user=> (def *x* 1) #'user/*x* user=> (doseq [y (map (fn [x] (* *x* x)) [1 2 3])] (println y)) 1 2 3 nil user=> (doseq [y (binding [*x* 2] (map (fn [x] (* *x* x)) [1 2 3]))] (println y)) 1 2 3 nil user=> (doseq [y (binding [*x* 2] (doall (map (fn [x] (* *x* x)) [1 2 3])))] (println y)) 2 4 6 nil The result of doall is a sequence that has already been evaluated. If you want a concrete sequence, you can get one: simply call seq on the output, or use vec or into. user=> (type (binding [*x* 2] (doall (map (fn [x] (* *x* x)) [1 2 3])))) clojure.lang.LazySeq user=> (type (seq (binding [*x* 2] (doall (map (fn [x] (* *x* x)) [1 2 3]))))) clojure.lang.ChunkedCons user=> (type (vec (binding [*x* 2] (doall (map (fn [x] (* *x* x)) [1 2 3]))))) clojure.lang.PersistentVector user=> (vec (binding [*x* 2] (doall (map (fn [x] (* *x* x)) [1 2 3])))) [2 4 6] > Also, having a dynamic var that turns laziness on and off would allow > you to do it once for any given scope, without having to add the extra > 'ceremony' of doalls. Sure, but it would either require complicating the core, or making functions that use lazy-seq pay attention to the binding of that var. Not fun -- it would introduce a problem that library authors have to think about. > I would add to that that casting your types back to what they were is > also unrealistic. I get the impression that programming with *abstractions* is the Clojure way. Dependence on particular sequence types is usually bad. If you need to, though, it's only a vec call away. If you call vec inside a binding form, you don't even need to realize the lazy sequence yourself. > If there were a *strict* dynamic var, then you \could choose code > simplification over laziness with a single line. What would be wrong > with that? To play devil's advocate: it complicates the implementation (and the implementation of libraries); the strictness would be undesirably viral (what if you accidentally cause a library to realize an infinite lazy sequence?); and for all I know it would screw up JIT optimization. My opinion is that an easier way to realize nested lazy sequences would be a more elegant solution to your problem; doall*, say. This could almost be implemented as (defmulti doall* class) (defmethod doall* clojure.lang.LazySeq [x] (seq (doall (map doall* x)))) (defmethod doall* :default [x] x) ... ;; Make some nested LazySeqs. user=> (type (map (fn [x] (repeat x :foo)) [1 2 3])) clojure.lang.LazySeq user=> (map type (map (fn [x] (repeat x :foo)) [1 2 3])) (clojure.lang.LazySeq clojure.lang.LazySeq clojure.lang.LazySeq) ;; Recursively eager evaluation. user=> (type (doall* (map (fn [x] (repeat x :foo)) [1 2 3]))) clojure.lang.ChunkedCons user=> (map type (doall* (map (fn [x] (repeat x :foo)) [1 2 3]))) (clojure.lang.Cons clojure.lang.Cons clojure.lang.Cons) You can omit the seq call in doall* if all you want is bindings capture/eager evaluation, and don't actually mind that it's LazySeq implementing ISeq rather than a 'concrete' sequence. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en