Losing your head with side effects

2011-10-25 Thread Mike
I need to read WAV files, and don't have time to recode the reader in
Clojure.  It's Java, and it's got side effects.  I can read a number
of frames from the WAV file with this code:

(defn read-frames [wav-file num-frames]
  (let [num-samples (* num-frames (.getNumChannels wav-file))
buffer (double-array num-samples)
frames-read (.readFrames wav-file buffer 0 num-frames)]
(if (= frames-read num-frames)
  (vec buffer)
  nil)))

So this is pretty straightforward...it uses this wav-file object,
calls .readFrames() on it which reads into an array of doubles (passed
in as buffer) and returns a vector of these values.  Every time you
call this function, it returns the next num-frames values as a vector,
so it's operating by side effects.

I want to make a seq of reading these frames.  I thought I might use
repeatedly, but it doesn't know to stop when the f returns nil.  So I
just coded it myself:

(defn wavfile-chunk-seq [num-frames wav-file]
  (lazy-seq (let [x (read-frames wav-file num-frames)]
  (if (nil? x)
'()
(cons x (wavfile-chunk-seq num-frames wav-file))

Only problem is, it's holding onto its head somehow.  When I (count
(wavfile-chunk-seq n wav-file)) and check memory, it's all still there
somehow.  I'm 99% positive the WAV file object in Java isn't retaining
the memory, because it uses a much smaller buffer.

Can anybody see what I'm doing wrong?  Maybe I should change my
approach, and try to generate a Java Iterator over these values, and
just use iterator-seq?

Thanks in advance for any ideas...
Mike

-- 
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: Losing your head with side effects

2011-10-25 Thread Mike
It appears I'm not understanding how something works in the REPL (or
maybe deeper).  For instance:

(def big (range 1000))
; memory is small now
(count big) = 1000
; memory is huge now
(System/gc)
; memory is still huge now
(def big nil)
(System/gc)
; memory is small again

So somehow when count realizes big, I'm guessing it gets memoized
and stuck in some sort of cache attached to the var big.

If I:

(do (System/gc) (count (range 1000)) (System/gc))
; memory is small before and after

I think the version I wrote originally is fine; I just wasn't testing
it properly.  Sorry to bother folks!

Mike

-- 
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: Losing your head with side effects

2011-10-25 Thread Linus Ericsson
Range is lazy.

First you define a range, which is just a promise that the variable will
be rendering a seq with 10M when asked for the elements.

When you count the sequence you realize it and it takes up much space. When
you let go if it it's of course GCed.

The problem is that you hold on to the head (first element) of the sequence.
If you do

(count (range 1000))

clojure will go through it lazily and throw away elements as they are
counted, hence much less memory usage.

Let go of the head! :)

/Linus

2011/10/25 Mike cki...@gmail.com

 It appears I'm not understanding how something works in the REPL (or
 maybe deeper).  For instance:

 (def big (range 1000))
 ; memory is small now
 (count big) = 1000
 ; memory is huge now
 (System/gc)
 ; memory is still huge now
 (def big nil)
 (System/gc)
 ; memory is small again

 So somehow when count realizes big, I'm guessing it gets memoized
 and stuck in some sort of cache attached to the var big.

 If I:

 (do (System/gc) (count (range 1000)) (System/gc))
 ; memory is small before and after

 I think the version I wrote originally is fine; I just wasn't testing
 it properly.  Sorry to bother folks!

 Mike

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