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

Reply via email to