Clojure lazy-seq over Java iterative code

2012-09-14 Thread Dave Kincaid


I also posted this to StackOverflow, so sorry if you saw it there too. If 
you want some rep points over there you can answer there too (
http://stackoverflow.com/questions/12427518/clojure-lazy-seq-over-java-iterative-code
).

I'm trying to use create a Clojure seq from some iterative Java library 
code that I inherited. Basically what the Java code does is read records 
from a file using a parser, sends those records to a processor and returns 
an ArrayList of result. In Java this is done by calling parser.readData(), 
then parser.getRecord() to get a record then passing that record into 
processor.processRecord(). Each call to parser.readData() returns a single 
record or null if there are no more records. Pretty common pattern in Java.

So I created this next-record function in Clojure that will get the next 
record from a parser.

(defn next-record
  Get the next record from the parser and process it.
  [parser processor]
  (let [datamap (.readData parser)
row (.getRecord parser datamap)]
(if (nil? row)
nil
(.processRecord processor row 100

The idea then is to call this function and accumulate the records into a 
Clojure seq (preferably a lazy seq). So here is my first attempt which 
works great as long as there aren't too many records:

(defn datamap-seq
  Returns a lazy seq of the records using the given parser and processor
  [parser processor]
  (lazy-seq
(when-let [records (next-record parser processor)]
  (cons records (datamap-seq parser processor)

I can create a parser and processor, and do something like (take 5 
(datamap-seq parser processor)) which gives me a lazy seq. And as expected 
getting the (first) of that seq only realizes one element, doing count 
realizes all of them, etc. Just the behavior I would expect from a lazy seq.

Of course when there are a lot of records I end up with a 
StackOverflowException. So my next attempt was to use loop-recur to do the 
same thing.

(defn datamap-seq
  Returns a lazy seq of the records using the given parser and processor
  [parser processor]
  (lazy-seq
(loop [records (seq '())]
  (if-let [record (next-record parser processor)]
(recur (cons record records))
records

Now using this the same way and defing it using (def results (datamap-seq 
parser processor)) gives me a lazy seq and doesn't realize any elements. 
However, as soon as I do anything else like (first results) it forces the 
realization of the entire seq.

Can anyone help me understand where I'm going wrong in the second function 
using loop-recur that causes it to realize the entire thing?

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

Re: Clojure lazy-seq over Java iterative code

2012-09-14 Thread Sean Corfield
On Fri, Sep 14, 2012 at 8:37 AM, Dave Kincaid kincaid.d...@gmail.com wrote:
 I also posted this to StackOverflow, so sorry if you saw it there too. If
 you want some rep points over there you can answer there too
 (http://stackoverflow.com/questions/12427518/clojure-lazy-seq-over-java-iterative-code).

Looks like there's already a good answer over there.

 Of course when there are a lot of records I end up with a
 StackOverflowException.

Did you dig into where the StackOverflowException originated from? As
noted in a comment on SO, the lazy-seq can handle millions of items
without a problem so the problem isn't inherently with that part of
your code. Perhaps it's the parser or the processor?
-- 
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/

Perfection is the enemy of the good.
-- Gustave Flaubert, French realist novelist (1821-1880)

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


Re: Clojure lazy-seq over Java iterative code

2012-09-14 Thread Dave Kincaid
Thanks, Sean. It turns out the exception is being thrown from one of the 
Java classes (I should have looked closer). I just assumed that doing the 
recursion without loop/recur would always blow the stack eventually. I'll 
have to do some research to understand when it does and when it doesn't.

I also pasted in the wrong original function that I was using when I was 
getting the exception. The code I pasted does work. The version that's 
making the Java code throw the exception has an extra (remove) in it to 
remove empty lists. It looks like this:

(defn datamap-seq
  Returns a lazy seq of the records using the given parser and processor
  [parser processor]
  (lazy-seq
(when-let [records (next-record parser processor)]
  (cons records (remove empty? (datamap-seq parser processor))

If I take out that remove and do it elsewhere it works fine. Still puzzling 
over that one.


On Friday, September 14, 2012 11:48:23 AM UTC-5, Sean Corfield wrote:

 On Fri, Sep 14, 2012 at 8:37 AM, Dave Kincaid 
 kincai...@gmail.comjavascript: 
 wrote: 
  I also posted this to StackOverflow, so sorry if you saw it there too. 
 If 
  you want some rep points over there you can answer there too 
  (
 http://stackoverflow.com/questions/12427518/clojure-lazy-seq-over-java-iterative-code).
  


 Looks like there's already a good answer over there. 

  Of course when there are a lot of records I end up with a 
  StackOverflowException. 

 Did you dig into where the StackOverflowException originated from? As 
 noted in a comment on SO, the lazy-seq can handle millions of items 
 without a problem so the problem isn't inherently with that part of 
 your code. Perhaps it's the parser or the processor? 
 -- 
 Sean A Corfield -- (904) 302-SEAN 
 An Architect's View -- http://corfield.org/ 
 World Singles, LLC. -- http://worldsingles.com/ 

 Perfection is the enemy of the good. 
 -- Gustave Flaubert, French realist novelist (1821-1880) 


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