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. So then the question becomes, why is my experience so different in other languages? Taking Scala as an example, I can think of two things that might make it more suitable in that language to work with non-cached lazy lists as a default. First, in Scala there is richer syntactic support for mutable, imperative-style programming when you need it. So you mostly use laziness, comprehensions, etc. with your immutable, functional-style code. But when you're working with mutable stuff (like interop with Java), you go ahead and code with for/while loops, assignment, and it doesn't feel particularly gross. Second, Scala has a more polymorphic approach to things like map and filter. If you map a vector, you get back a vector. If you filter a concrete list, you get back a concrete list. Comprehension syntax is essentially a macro that expands to combinations of map, filter, and flatMap (analogous to Clojure's mapcat, I think), so your comprehension output is also determined by the type of the first collection in the comprehension. So if you're working with mutable data, you'd be storing it in a different kind of collection anyway (like a vector, or a cached lazy list), and all the map, filter, etc. would work the way you'd expect it to. The first point can just be chalked up to rather fundamental design differences in the two languages. Incorporating this kind of "imperative subsystem" would clutter up Clojure's elegance. 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. 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. --Mark P.S. I don't want to sound too negative, so I'll mention here that there are several things I *love* about Clojure. First, the way operations on so many of the data structures are unified through the sequence interface. Second, multimethods (haven't seen much multimethod action since Dylan, and I've always loved them). Third, many little touches like making maps, sets, vectors, and keys also act like function, which contribute to readable brevity. --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---