Reducers [1] provide eager variants of some core seq functions (map, filter, etc.). Note that they do not cache the result, so they recompute it every time you use their result.
[1] http://clojure.org/reducers On Mon, Jun 2, 2014 at 10:32 PM, Lee Spector <lspec...@hampshire.edu> wrote: > > I've generally liked Clojure's pervasive laziness. It's cute and it > sometimes permits lovely, elegant approaches to particular programming > problems. And although I've long known that it can get you into trouble in > a few unusual cases -- I think I recall seeing a nice blog post on issues > related to "binding" and laziness by Chas Emerick several years ago -- it > has generally seemed safe enough for most purposes. I figured that while it > may not always provide benefits it should at least be mostly harmless. > > However, after spending a couple of days tracking down a particularly > confusing bug, and finding once again (this has happened to me at least a > few times) that the bug was due to laziness that I never really wanted in > the first place, I'm reconsidering. > > I don't have a pared-down version of the bug that I was just dealing with > (see below for a pointer to the non-pared-down version), but it goes away > when I wring out all of the laziness. In this particular case I do so by > calling vec or doall on the results of all of my calls to map and other > functions function that produce lazy sequences (none of which I actually > want to be lazy in this application). I was getting StackOverflowErrors and > I have a half-baked half-theory that it was due to some bad interaction > between laziness and garbage collection, with the JVM not realizing that it > could reclaim lazy things that weren't yet fully evaluated. That doesn't > make complete sense to me, and maybe that kind of bad interaction is not > even possible -- I don't know. But I do know that all is well when I wring > out all of the laziness. > > One possible lesson from this experience (which was particularly > frustrating, BTW, because the stack backtraces were particularly > uninformative [1]) is that I should just be careful to surround any call to > any function that produces a lazy sequence with something like vec that > ensures that the laziness will be eliminated as soon as it is created -- > except in those relatively rare cases where I really want the laziness. But > this would be a pain, and ugly. I rely heavily on Clojure's sequence > processing functions and I would hate to clutter up every call to every one > of them or to have to reimplement my own non-lazy versions of everything. > > Is there a more elegant way? Maybe somebody has already made non-lazy > clones of all of the core functions that normally produce lazy sequences? > And if so, maybe there's some clean way to cause my code to use the > non-lazy versions unless specifically directed to use the lazy versions? > > I realize that this is fighting with a core feature of Clojure, and that > the idea will probably rub lots of folks the wrong way. But I've now been > down this road a couple of times and I'm beginning to think that I'd spend > less time tracking down mysterious bugs if I could avoid laziness more > easily. > > In case anybody is motivated to look into the specific bug that I was just > dealing with, I've put the project at > http://hampshire.edu/lspector/temp/world2D.zip. If you do "lein run" in > its present state it will run fine, making little balls bounce around. > (This is a very early version of some code that I plan to use both for > teaching an AI class and for some ALife experiments...) But if you edit > src/world2D/vec2D.clj, commenting out the definitions of *v, +v, and -v, > and uncommenting the alternatives (which are the same except that they lack > the calls to vec) then after running for a few seconds or a minute or so > you'll get the stack overflow. > > Thanks for any suggestions, > > -Lee > > > [1] The stack traces I was getting provide no information about where/what > the offending lazy sequences are, since they don't show locals etc. I see > no references to any of my own code, just a repeating sequence that starts: > > StackOverflowError > clojure.core/seq (core.clj:133) > clojure.core/map/fn--4211 (core.clj:2490) > clojure.lang.LazySeq.sval (LazySeq.java:42) > clojure.lang.LazySeq.seq (LazySeq.java:60) > clojure.lang.RT.seq (RT.java:484) > clojure.core/seq (core.clj:133) > clojure.core/map/fn--4211 (core.clj:2490) > clojure.lang.LazySeq.sval (LazySeq.java:42) > clojure.lang.LazySeq.seq (LazySeq.java:60) > clojure.lang.RT.seq (RT.java:484) > [etc] > > -- > 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 > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.