> 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

Reply via email to