On Fri, Dec 12, 2008 at 10:09 PM, Mark Engelberg <mark.engelb...@gmail.com> wrote: > > On Fri, Dec 12, 2008 at 5:28 PM, Paul Mooser <taron...@gmail.com> wrote: >> >> On Dec 12, 3:15 pm, "Mark Engelberg" <mark.engelb...@gmail.com> wrote: >>>And in fact, it turns out that in those languages, uncached lazy lists end >>>up rarely used. >> >> Did you mean that the cached lazy lists are rarely used? Or does >> everyone actually choose to use the cached ones? > > Sorry, in that particular sentence I said the opposite of what I > meant. I meant that cached lazy lists are rarely used in those > languages. > > Although I'm a relative newbie to Clojure, I've spent a lot of time > using a wide variety of languages. When Rich's reaction was > "everything mutable breaks without caching", my initial reaction was > astonishment that he perceives that to be the common case in a > language where mutability is mostly shunned. I have trouble thinking > of a case where I'd want to put something mutable in a lazy list. But > of course, he's spent more time with Clojure than anyone, so I don't > doubt his experience on this matter.
I wasn't talking at all about lists of mutable things. In Clojure, people often build a sequence from an imperative/ephemeral source. The caching becomes very important in these cases. > As to the second point, it's not inconceivable to do something like > that in Clojure. Clojure's multimethods can certainly support such a > thing. But certainly Scala's approach has a downside because > sometimes you don't want a comprehension to build the same thing as > the source collection, and converting between them can be inefficient. > There's something rather nice about the way Clojure always returns a > bland sequence that can essentially be "realized" into anything you > want. It just seems unfortunate to me that a consequence of this is > that all these output sequences are automatically of the cached > variety. > > Perhaps there's some sort of middle ground where Clojure can always > return a lazy sequence, but be a bit more intelligent about choosing > the right variety depending on the nature of the input, but it's not > immediately apparent to me how one would do that. If I get a chance, > I'll definitely play around with some of these ideas, as Rich > suggested, although my "common case" programming seems to be different > from his. I got burned by the filter issue on my very first Clojure > program, when I tried to filter a lazy stream of 10-digit permutations > to find all the permutations with a certain property. The > permutations which satisfied the property were far enough apart that > it caused a problem. This is the kind of program I typically write. > I'm sorry you encountered a bug, and will fix, but that's not an indictment of Clojure's approach. Scala et al have had their own problems: http://lampsvn.epfl.ch/trac/scala/ticket/692 http://lampsvn.epfl.ch/trac/scala/ticket/498 http://groups.google.com/group/cal_language/browse_thread/thread/728a3d4ff0f77b00 Note that Clojure does do locals nulling on tail calls. It certainly has paid attention to laziness implementation issues, a bug notwithstanding. > In the meantime, I'm definitely looking forward to seeing Rich's new > generator approach. Maybe having another way to tackle the problem > cases will make a lot of my worries about this issue go away. > I think it's very important not to conflate different notions of sequences. Clojure's model a very specific abstraction, the Lisp list, originally implemented as a singly-linked list of cons cells. It is a persistent abstraction, first/second/third/rest etc, it is not a stream, nor an iterator. Lifting that abstraction off of cons cells doesn't change its persistent nature, nor does lazily realizing it. After my experimentation with a non-caching version, I am convinced it is incompatible with the abstraction. If a seq was originally generated from an imperative source, you need it to be cached in order to get repeatable read persistence, if it was calculated at some expense, you need to cache it in order to get the performance characteristics you would expect from a persistent list. An abstraction is more than just an interface. That said, I think there is certainly room for a stream/generator model, especially for I/O, but also for more efficient collection processing. Such a thing is explicitly one-pass and ephemeral. It will not have the interface of first/rest, nor Java's thread-unsafe hasNext/next iterator model (shared by Scala). You can obviously build seqs from streams/generators, and in my model, with a single definition you will get both a stream and seq version of functions like map and filter, as I showed here: http://groups.google.com/group/clojure/msg/53227004728d6c54 Note also that filter/map etc are not part of these abstractions, though they can be defined on top of both. Stream/generators and a corresponding map/filter library on them will give you other options for one-pass processing, but lazy seqs work pretty well right now. Rich --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---