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