On Jun 12, 2009, at 7:52 PM, Wrexsoul wrote:

> Well, I did it. Made implementing lazy seqs that require stateful
> generator functions easy, that is:
>
> (defn files-and-dirs-recursive [dir]
>  (super-lazy-seq [stack [(to-file dir)]]
>    (if-not (empty? stack)
>      (let [file (first stack) s (rest stack)]
>        (next-item
>          file
>          (if (directory? file)
>            (concat s (files-and-dirs file))
>            s))))))


Before we order the cake, let's compare to Clojure's own implementation:

(defn tree-seq
   "Returns a lazy sequence of the nodes in a tree, via a depth-first  
walk.
    branch? must be a fn of one arg that returns true if passed a node
    that can have children (but may not).  children must be a fn of one
    arg that returns a sequence of the children. Will only be called on
    nodes for which branch? returns true. Root is the root node of the
   tree."
    [branch? children root]
    (let [walk (fn walk [node]
                 (lazy-seq
                  (cons node
                   (when (branch? node)
                     (mapcat walk (children node))))))]
      (walk root)))

(defn file-seq
   "A tree seq on java.io.Files"
   [dir]
     (tree-seq
      (fn [#^java.io.File f] (. f (isDirectory)))
      (fn [#^java.io.File d] (seq (. d (listFiles))))
      dir))

No macros. No magic names. No explicit state. Easier to explain. Same  
result.

On Jun 13, 2009, at 9:37 PM, Wrexsoul wrote:

> When clojure.contrib releases version 1.0, that might be an option.


One of the many things I hated about other languages was the  
maddeningly incipient libraries. With Rails, for example, the  
documentation was always a blog post telling you to check out the  
latest version of the source from GitHub, where you would go to find  
it abandoned and the developed fork of someone's fork of it would have  
a different, undocumented API, and then you'd find out it doesn't work  
in your one-minor-release-old version of Rails... etc.

But let's face it; we're using a language whose 1.0 release was less  
than two months ago. Stability is something I would expect to see in  
Clojure in 3-5 years, not next month. Everyone uses Contrib; it's  
almost an incubator for future core functionality. I can't imagine  
using Clojure without duck-streams.

On Jun 14, 2009, at 9:58 PM, Wrexsoul wrote:

> Of course, super-lazy-seq:
> a) does the wrapping AND unwrapping for you
> b) manages the rebinding each iteration for you,
>   transparently and
> c) works just as well.

I think the amount of debate we've seen about it here is sufficient  
proof that, though it works just as well, there is a certain funk to  
it. Personally, I don't like macros whose expansion involves magic  
names. What happens if you nest them—intentionally or accidentally?  
Also, this violates another principle of good macro writing, which is  
that it does not wrap a function call. Generally that means there are  
situations where you can't get the benefit dynamically.

> The loop/recur style of super-lazy-seq use seems "closer to
> functional purity" than does an explicitly stateful genfn.

True, but tree-seq manages the same task with no explicit state at  
all. And while we can certainly embark on a debate about whether or  
not it is more functional to recur or to compose functions, I think we  
can agree that doing something with a macro that could be done with a  
regular function is something other than functional. If functional  
purity is something we are deeply concerned about.

> One thing is becoming clear: in clojure, there's generally more than
> one way to do it. Whatever "it" is.


Agreed! And that all of the options can have their own pragmatic  
reasoning behind them is great, IMO.

I do wonder about the interaction between garbage collection and  
lazily computed resources. The example code for dealing with databases  
in the Clojure book seemed to materialize the rows before returning  
them, which seems like a waste of good laziness, but it probably  
avoids exactly these kinds of problems. Until I run into actual issues  
on my own, though, I'm going to let this problem remain theoretical  
and hope that one of the great minds working on the core can find a  
solution. For some reason I believe there will probably be a good  
solution to this, if not generally, then at least in the 80% cases we  
are likely to run into.

—
Daniel Lyons
http://www.storytotell.org -- Tell It!


--~--~---------~--~----~------------~-------~--~----~
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