Re: super-lazy-seq
On Jun 14, 2:53 pm, James Reeves wrote: > On Jun 14, 6:32 pm, Wrexsoul wrote: > > > I wrote super-lazy-seq because repeatedly can't generate a finite > > sequence. It just spat out > > > (File1 File2 File3 File4 nil nil nil nil nil nil nil ... > > Well, you could wrap it in take-while: > > (defn custom-lazy-seq [stream] > (take-while (complement nil?) > (repeatedly #(next-item-in-seq stream Eh. That didn't occur to me. It could be combined with the meta-nil trick, too: (defn custom-lazy-seq [genfn] (map #(first %) (take-while (complement nil?) (repeatedly genfn where the genfn returns nil for no-next-item and [item] otherwise. Of course, super-lazy-seq: a) does the wrapping AND unwrapping for you b) manages the rebinding each iteration for you, transparently and c) works just as well. The loop/recur style of super-lazy0-seq use seems "closer to functional purity" than does an explicitly stateful genfn. One thing is becoming clear: in clojure, there's generally more than one way to do it. Whatever "it" is. --~--~-~--~~~---~--~~ 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: Primitive char Type
On Jun 13, 2009, at 10:46 PM, Stephen C. Gilardi wrote: user=> (.setCharAt s 0 \c) java.lang.IllegalArgumentException: Can't call public method of non- public class: public void java.lang.AbstractStringBuilder.setCharAt(int,char) (NO_SOURCE_FILE:0) I'm not sure why. StringBuilder extends AbstractStringBuilder (though the JavaDoc docs lie and say it extends Object). AbstractStringBuilder has default accessibility (not public, protected, or private) which makes the class inaccessible to code outside the java.lang package. In both Java SE 5 and Java SE 6, StringBuilder does not contain a .setCharAt method definition. It relies on the inherited public method in AbstractStringBuilder. (I downloaded the source code for both versions from Sun to check.) In Java SE 5, when Clojure checks whether or not .setCharAt on StringBuilder is public, it finds that it's a public method of a non- public base class and throws the exception you saw. (It looks like you're using a version of Clojure older than 18 May 2009 (Clojure svn r1371). Versions later than that print the more detailed message I saw.) In Java SE 6, Clojure's checks for accessibility of this method succeed and the method call works. I'm not sure whether or not Clojure could be modified to make this method call work in Java 5. Google searches turn up discussion that this pattern of using an undocumented abstract superclass with non- public accessibility is not common in the JDK. --Steve smime.p7s Description: S/MIME cryptographic signature
Re: Arraylist faster than primitive array?
It looks like a case of reflection being used. I would set *warn-on-reflection* to true, and just check which method is not being resolved. My guess is probably the aset. (aset arlist (int i) (int 1)) would probably fix it. -Patrick --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
dosync ref-set and threads coordination problem
In the example below 256 clients threads put a byte (0-255) to server- socket reference var "items", then connect to server-socket, write the same byte to socket stream and close the connection. The server connections threads reads a byte from the socket stream and remove it from the var "items". At the end of the run i expect the var items to be empty but it is not. It 's contains a random number of bytes. Where is the error? (ns test-dosync (:import (java.net Socket)) (:use clojure.contrib.server-socket)) (def server (let [items (ref nil) server-ref (ref nil) server-fn (fn [ins _] (let [bt (.read ins)] (dosync (ref-set items (remove #(= % bt) @items)] {:enq (fn [item] (dosync (alter items conj item))) :list-items (fn [] @items) :start (fn [port] (let [socket-server (create-server port server-fn)] (dosync (ref-set items nil) (ref-set server-ref socket-server :stop (fn [] (when @server-ref (close-server @server-ref))) })) (defn start-server [port] ((:start server) port)) (defn stop-server [] ((:stop server))) (defn enq [id] ((:enq server) id)) (defn list-items [] ((:list-items server))) (defn client-fn [port #^Byte byte-to-send] #(let [socket (Socket. "localhost" port) outs (.getOutputStream socket)] (try (do (enq byte-to-send) (doto outs (.write byte-to-send) (.flush))) (finally (.close socket) (defn run-test [] (try (let [port 10002] (start-server port) (dorun (apply pcalls (map #(client-fn port %) (range 256) (finally (stop-server))) (list-items)) --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
Arraylist faster than primitive array?
If I run this code: (def ibounds 100) (let [arlist (new java.util.ArrayList ibounds)] (dotimes [i ibounds] (.add arlist 0)) (time (dotimes [x 100] (dotimes [i ibounds] (.set arlist i 1) (let [arlist (make-array Integer/TYPE ibounds)] (time (dotimes [x 100] (dotimes [i ibounds] (aset arlist i 1) The output is: "Elapsed time: 1207.023797 msecs" "Elapsed time: 11569.701736 msecs" nil Is this normal behavior or am I doing something wrong? --~--~-~--~~~---~--~~ 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 equivalent to Ruby's ERB
markgunnels, Have you used clojure and StringTemplate to do something? If so, I would like to tap your knowledge there. Regards, Emeka On Sun, Jun 14, 2009 at 1:36 PM, markgunnels wrote: > > I just wanted to report back that StringTemplate proved to be the > perfect solution. > > I also wanted to recommend Terrence Parr's (the creator and ANTLR and > StringTemplate) new book Language Design Patterns from The Pragmatic > Programmers for anyone doing parsing and code generation. It is an > excellent introduction to the subject. > > On May 27, 6:02 pm, Stuart Sierra wrote: > > On May 26, 10:47 pm,markgunnels wrote: > > > > > Hopefully this doesn't get me booed off the message board but is there > > > a Clojure equivalent to Ruby's ERB? I'm try to use Clojure to perform > > > code generation > > > > I've had success with StringTemplate. Very functional design, easy to > > call from Clojure. And it's designed for code generation (the ANTLR > > parser generator). > > > > -Stuart Sierra > > > --~--~-~--~~~---~--~~ 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: super-lazy-seq
On Jun 14, 6:32 pm, Wrexsoul wrote: > I wrote super-lazy-seq because repeatedly can't generate a finite > sequence. It just spat out > > (File1 File2 File3 File4 nil nil nil nil nil nil nil ... Well, you could wrap it in take-while: (defn custom-lazy-seq [stream] (take-while (complement nil?) (repeatedly #(next-item-in-seq stream - James --~--~-~--~~~---~--~~ 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: Performance Penalty Converting from Java Code
kedu Travis, (defn base26 [ n] (let [seed-string "" s (new StringBuilder seed-string)] (loop [ pos (- (count seed-string) 1) x n] (if (and (> pos 0)(> x 0)) (do (. s setCharAt pos (char (+ (int \a) (mod x 26 (recur (- pos 1) (/ x 26) (. s toString))) (doseq [i (range (Math/pow 26 4))] (base26 i)) Try the above. Emeka --~--~-~--~~~---~--~~ 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: catching exception error
Thanks for your answers. I read the thread and understood why I don't get my IllegalArgumentException but a new RuntimeException that wrapps it. But I don't understand what the reason is to create a new RuntimeException (stack tracing?) knowing that IllegalException is a subclass of RuntimeException so that it could be thrown directly form clojure core code. --~--~-~--~~~---~--~~ 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: super-lazy-seq
On Jun 14, 9:39 am, James Reeves wrote: > Okay, but don't underestimate the power of higher level functions. I > don't know whether it would apply to your code, but the repeatedly > function can be used to create a lazy seq from a function with side- > effects. > > For example: > > (defn custom-lazy-seq [stream] > (repeatedly #(next-item-in-seq stream))) I wrote super-lazy-seq because repeatedly can't generate a finite sequence. It just spat out (File1 File2 File3 File4 nil nil nil nil nil nil nil ... :) --~--~-~--~~~---~--~~ 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: Performance Penalty Converting from Java Code
On Jun 14, 7:00 pm, tmountain wrote: > I've been playing around with rewriting some Java code in Clojure and > did some simple benchmarking in the process. In this case, there's a > huge disparity in the performance numbers between the two languages, > and I'm wondering what the cause may be. The program rotates a string > from "", "aaab", ..., "". The Java version takes 0.77 seconds > to complete while the Clojure version takes 22 seconds. I've tried to > make the scripts relatively isomorphic and have verified that they > produce the same results. I'm pasting the source below. > Here is a clojure version that runs significantly faster on my system. The main optimizations I have done are coercion to primitives and using unchecked ops. As I understand it, the original clojure version is slow because its safer (checks for overflows etc.). (defn xbase26 [n] (let [seed-string "" s (new StringBuilder seed-string) a_val (int \a)] (loop [pos 3 x (int n)] (when (pos? x) (let [digit (char (+ a_val (unchecked-remainder x 26)))] (.setCharAt s pos digit) (when (pos? pos) (recur (int (dec pos)) (unchecked-divide x 26)) (.toString s))) These are the numbers I see: ;; java [clojure]% time java -cp . Base26 java -cp . Base26 0.40s user 0.02s system 88% cpu 0.476 total ;; original [clojure]% time java -cp .:classes:/home/parthm/src/clojure/ clojure.jar base26 java -cp .:classes:/home/parthm/src/clojure/clojure.jar base26 33.08s user 1.18s system 99% cpu 34.456 total [clojure]% ;; optimized [clojure]% time java -cp .:classes:/home/parthm/src/clojure/ clojure.jar base26 java -cp .:classes:/home/parthm/src/clojure/clojure.jar base26 1.75s user 0.11s system 104% cpu 1.784 total While this works well, I more optimization may be possible by choosing an algorithm thats more suited and ideomatic for clojure. I suppose that intent here is to do a micro-benchmark. Regards, Parth > tra...@travis-ubuntu:/tmp% time clj base26.clj > clj base26.clj 21.99s user 1.23s system 85% cpu 27.318 total > > tra...@travis-ubuntu:/tmp% time java Base26 > java Base26 0.77s user 0.04s system 78% cpu 1.029 total > > clojure version: > > (defn base26 [n] > (let [seed-string "" > s (new StringBuilder seed-string)] > (loop [pos (- (count seed-string) 1) > x n] > (if (> x 0) > (let [digit (+ (int \a) (mod x 26))] > (. s setCharAt pos (char digit)) > (if (and (> pos 0) (> x 0)) > (recur (- pos 1) (/ x 26)) > (. s toString))) > > (doseq [i (range (Math/pow 26 4))] > (base26 i)) > > java version: > > import java.lang.StringBuilder; > > public class Base26 { > public static void main(String[] args) { > for (int i = 0; i < Math.pow(26, 4); i++) { > Base26.base26(i); > } > } > > public static String base26(int num) { > if (num < 0) { > throw new IllegalArgumentException("Only positive numbers > are supported"); > } > StringBuilder s = new StringBuilder(""); > for (int pos = 3; pos >= 0 && num > 0 ; pos--) { > char digit = (char) ('a' + num % 26); > s.setCharAt(pos, digit); > num = num / 26; > } > return s.toString(); > } > > } > > I've tried warn-on-reflection, and it didn't report anything. > > Thanks, > Travis --~--~-~--~~~---~--~~ 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: Primitive char Type
That doesn't work either. It appears this isn't an issue with Java 6, but that doesn't help me on my PPC powerbook, which is apparently stuck with the Java 5 JRE for the foreseeable future. Thanks, Travis On Jun 14, 10:44 am, James Reeves wrote: > On Jun 14, 3:28 am, tmountain wrote: > > > java.lang.IllegalArgumentException: No matching method found: > > setCharAt for class java.lang.StringBuilder (NO_SOURCE_FILE:0) > > user=> (type (char \a)) > > java.lang.Character > > ; should be char? > > You could try: (.charValue \a) > > - James --~--~-~--~~~---~--~~ 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: Primitive char Type
On Jun 14, 3:28 am, tmountain wrote: > java.lang.IllegalArgumentException: No matching method found: > setCharAt for class java.lang.StringBuilder (NO_SOURCE_FILE:0) > user=> (type (char \a)) > java.lang.Character > ; should be char? You could try: (.charValue \a) - James --~--~-~--~~~---~--~~ 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: Primitive char Type
On Jun 14, 4:40 am, Wrexsoul wrote: > What I miss is foo-array for foo not in #{int long float double}, > particularly for (= foo byte). You can use (make-array Byte/TYPE size) and (into-array Byte/TYPE byte- coll). - James --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
Performance Penalty Converting from Java Code
I've been playing around with rewriting some Java code in Clojure and did some simple benchmarking in the process. In this case, there's a huge disparity in the performance numbers between the two languages, and I'm wondering what the cause may be. The program rotates a string from "", "aaab", ..., "". The Java version takes 0.77 seconds to complete while the Clojure version takes 22 seconds. I've tried to make the scripts relatively isomorphic and have verified that they produce the same results. I'm pasting the source below. tra...@travis-ubuntu:/tmp% time clj base26.clj clj base26.clj 21.99s user 1.23s system 85% cpu 27.318 total tra...@travis-ubuntu:/tmp% time java Base26 java Base26 0.77s user 0.04s system 78% cpu 1.029 total clojure version: (defn base26 [n] (let [seed-string "" s (new StringBuilder seed-string)] (loop [pos (- (count seed-string) 1) x n] (if (> x 0) (let [digit (+ (int \a) (mod x 26))] (. s setCharAt pos (char digit)) (if (and (> pos 0) (> x 0)) (recur (- pos 1) (/ x 26)) (. s toString))) (doseq [i (range (Math/pow 26 4))] (base26 i)) java version: import java.lang.StringBuilder; public class Base26 { public static void main(String[] args) { for (int i = 0; i < Math.pow(26, 4); i++) { Base26.base26(i); } } public static String base26(int num) { if (num < 0) { throw new IllegalArgumentException("Only positive numbers are supported"); } StringBuilder s = new StringBuilder(""); for (int pos = 3; pos >= 0 && num > 0 ; pos--) { char digit = (char) ('a' + num % 26); s.setCharAt(pos, digit); num = num / 26; } return s.toString(); } } I've tried warn-on-reflection, and it didn't report anything. Thanks, Travis --~--~-~--~~~---~--~~ 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: super-lazy-seq
On Jun 14, 4:37 am, Wrexsoul wrote: > Seems to me that unless you completely consume the sequence, it will > leak a file handle. That's true, but that's a problem that affects all seqs. There's no current way to mark a seq that comes from a stream as being discarded or closed, except by closing the initial stream. > OK. Even so, the implementation in terms of super-lazy-seq shows the > power of that macro. Mostly, I'm doing quite a few things with I/O > that require custom next-item-in-seq generators for the records or > other objects returned, for which it's coming in real handy. Okay, but don't underestimate the power of higher level functions. I don't know whether it would apply to your code, but the repeatedly function can be used to create a lazy seq from a function with side- effects. For example: (defn custom-lazy-seq [stream] (repeatedly #(next-item-in-seq stream))) - James --~--~-~--~~~---~--~~ 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 equivalent to Ruby's ERB
I just wanted to report back that StringTemplate proved to be the perfect solution. I also wanted to recommend Terrence Parr's (the creator and ANTLR and StringTemplate) new book Language Design Patterns from The Pragmatic Programmers for anyone doing parsing and code generation. It is an excellent introduction to the subject. On May 27, 6:02 pm, Stuart Sierra wrote: > On May 26, 10:47 pm,markgunnels wrote: > > > Hopefully this doesn't get me booed off the message board but is there > > a Clojure equivalent to Ruby's ERB? I'm try to use Clojure to perform > > code generation > > I've had success with StringTemplate. Very functional design, easy to > call from Clojure. And it's designed for code generation (the ANTLR > parser generator). > > -Stuart Sierra --~--~-~--~~~---~--~~ 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: super-lazy-seq
On Jun 14, 6:37 am, Wrexsoul wrote: > On Jun 13, 11:07 pm, James Reeves wrote: > > > For instance, lets say I want to return a lazy list of all the lines > > in all the files in a directory tree: > > > (use '(clojure.contrib java-utils > > duck-streams)) > > When clojure.contrib releases version 1.0, that might be an option. > Most interesting Clojure projects already depend on contrib in some form. You will need it eventually :) And frankly, the main reason there is not a 1.0 of contrib yet is that no-one has bothered to tag one. :P > > (defn all-line-seq [dir] > > (mapcat read-lines (file-seq (file dir > > > Since file-seq, read-lines and mapcat all lazy, my final result is > > lazy as well. > > Seems to me that unless you completely consume the sequence, it will > leak a file handle. That's a problem with lazy seqs and IO in general. You just need to be careful. IIRC Rich is working on a solution, though. > > > Is file-seq recursive? I'd figured it just returned the flat contents > > > of a directory. > > > Yep, it's recursive. > > OK. Even so, the implementation in terms of super-lazy-seq shows the > power of that macro. Mostly, I'm doing quite a few things with I/O > that require custom next-item-in-seq generators for the records or > other objects returned, for which it's coming in real handy. In those > circumstances lazy-seq saves the bother of doing a loop/recur in > everyplace that consumes some records, and super-lazy-seq in turn lets > me still use a loop/recur style in the one place where the code > extracts and grovels over the records one by one. Maybe I'm just thick, but why would you want to use loop/recur style when the following works: (defn items-from-stateful-source [src] (when-let [item (take-item src)] ; take-item returns nil when there are no more items (lazy-seq (cons item (items-from-stateful-source src) Maybe I'm just too infatuated with higher-order functions and recursion. looping constructs are boring :) --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
On Jun 14, 5:31 am, Max Suica wrote: > > A lazy right fold[1] allows short-circuiting, so here's one attempt: > > Wow, that made my head explode. > > Some points: > > 1) That's not exatly foldr, as (foldr + 0 [range 100]) ought to work Agreed, having to write that as (foldr (fn [x f-rest] (+ x (f-rest))) 0 (range 100)) shows that deficiency rather quickly. > 2) Foldr is not tail recursive nor can you really call an anamorphism > lazy The function I posted wasn't tail recursive either. It called the passed in f on the (delayed) result of the recursion before returning. It's certainly lazy on the spine of the list, in that evaluation is deferred until the caller needs a value, just like foldr should be. It's the inability to delay evaluation of arbitrary args (the recursion, here) that keeps us from being able to write, say, (foldr + 0 [1..10]) and have it work. > 3) Never the less you did it, through some mind twisting continuation > passing style > 4) That's fn awesome :D where did you learn it? There're three ways to defer evaluation that I know of in Clojure: delayed macro evaluation, force/delay, and what you see. The macro approach doesn't really work, the force/delay looks even worse, so ... -Sudish --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
I'm sorry, folds are catamorphisms, while stuff like (repeatedly f) or (repeat n x) are anamorphisms, and can certainly be lazy. --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
> A lazy right fold[1] allows short-circuiting, so here's one attempt: Wow, that made my head explode. Some points: 1) That's not exatly foldr, as (foldr + 0 [range 100]) ought to work 2) Foldr is not tail recursive nor can you really call an anamorphism lazy 3) Never the less you did it, through some mind twisting continuation passing style 4) That's fn awesome :D where did you learn it? -max --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
On Jun 14, 5:04 am, Max Suica wrote: > (defn interesting? [pixels in-range? count] > (let [p-count (reduce-bail (fn [c p] (if (in-range? p) (inc c) c)) > (partial > count) 0 pixels)] > [( = count yummy-pix-count) p-count])) Shoot: s/[( = count yummy-pix-count) p-count]))/[( = count p-count) p- count])) And wow, writing literate programs is not facilitated by this forum! Here's the whole listing in copy/paste friendly form: (defn reduce-bail [f pred? val col] (let [s (seq col)] (if s (if (pred? val) (recur f pred? (f val (first s)) (next s)) val) val))) (defn interesting? [pixels in-range? count] (let [p-count (reduce-bail (fn [c p] (if (in-range? p) (inc c) c)) (partial > count) 0 pixels)] [( = count p-count) p-count])) (interesting? (let [r (take 1000 (repeatedly #(rand-int 10)))] (println (count (filter #(= % 5) r ))) r) #(= % 5) 93) (interesting? (repeatedly rand) #(> % 0.99) 1000) --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
Laurent, I think this is a close variant of the early exiting reduce function you proposed: (defn reduce-bail [f pred? val col] (let [s (seq col)] (if s (if (pred? val) (recur f pred? (f val (first s)) (next s)) val) val))) ;Then we can write: (defn interesting? [pixels in-range? count] (let [p-count (reduce-bail (fn [c p] (if (in-range? p) (inc c) c)) (partial > count) 0 pixels)] [( = count yummy-pix-count) p-count])) ; This returns a vec showing how close to the interesting count the pixels came in addition to showing whether the sequence was interesting, so that we see that it works. ; Now, in completely terrible form precipitated by the fact that it's 4:20 in the morning we try: (interesting? (let [r (take 1000 (repeatedly #(rand-int 10)))] (println (count (filter #(= % 5) r ))) r) #(= % 5) 93) ; This bails according to the number of 5s counted, but also side effects the printing of a complete count to show that it works. (interesting? (repeatedly rand) #(> % 0.99) 1000) ; Here, we see that our cautious reduce does not choke on infinite sequences if it can escape. It will not halt for uninteresting sequences however, so this isn't useful here. Way too tired right now to think about whether this is useful in general (Maybe in cases where you're looking to bail at some value more complicated than a count), but the code runs pretty neat, and I agree with Laurent that we should explore this abstraction. Dunno if there are hidden bugs in my code tho. Anyways. Sleepytime - max --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
On Jun 13, 4:39 pm, Laurent PETIT wrote: > Hi, > > Well, the array is iterated once by map, the new seq created by map is > iterated once by filter, and the new seq created by filter is iterated > once by count, so right, I should have written : 3 walks of seqs of > the size of the array. Hi Laurent, I'm probably misunderstanding what you mean by size of the array here, but since all of this is lazy map will only walk as far as take-while lets it, right? I.e., just far enough to make the take-while happy and not the whole array. (defn f [x] (print (str "x: " x "\n")) (inc x)) user> (count (take-while #(< % 10) (map f (iterate inc 0 x: 0 x: 1 x: 2 x: 3 x: 4 x: 5 x: 6 x: 7 x: 8 x: 9 9 > While reduce would create no new seq, and one walk ? I guess it's a matter of perspective as to whether there's one walk or multiple as the combined lazy-seq gets "pulled" by count -- I tend to think of it as an assembly line with multiple stations on it (one, lengthy "walk" :-). Yes, like you said, there's double the consing (or triple with a filter as in the original example). However, isn't the JVM supposed to excel at allocating/collecting just this kind of very short-lived data/ garbage? The (count (take-while (filter (map just feels very natural in clojure to me. -Sudish --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
On Jun 13, 4:17 pm, Laurent PETIT wrote: > So it really seems to me that the missing abstraction, here, is being > able to do a reduce over the list of pixels, and being able, from the > reduction function, to quit the reduction early. A lazy right fold[1] allows short-circuiting, so here's one attempt: (defn foldr "Implements a lazy right fold of the function f on coll. f should be a function of two arguments: the next element to be consumed, and a function which returns the result of folding the rest of the list. The reduction starts at the end of the list by calling f with the last element and val." [f val coll] (if-let [s (seq coll)] (f (first s) (fn [] (foldr f val (rest s val)) (defn interesting? [pixels c] (let [f (fn [pixel counter] (if (< pixel c) (inc (counter)) 0))] (foldr f 0 pixels))) (interesting? (iterate inc 0) 10) => 10 The need to exlictly call the lazy thunk passed as the second argument feels a little weird, but it does give us a lazy "right reduce" that can short-circuit the reduction when it's done. Here's a lazy filter function implemented using foldr: (defn foldr-filter [pred coll] (let [f (fn [x accum] (if (pred x) (cons x (accum)) nil))] (foldr f nil coll))) (take 20 (foldr-filter (fn [x] (< x 10)) (iterate inc 0))) => (0 1 2 3 4 5 6 7 8 9) Cheers, -Sudish [1] http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29#Evaluation_order_considerations --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
2009/6/14 James Reeves : > > On Jun 13, 9:57 pm, Laurent PETIT wrote: >> > The filter and map functions produce lazy seqs, so the sequence is >> > only walked once. >> >> Well, isn't walking 3 different sequences 1 time almost equivalent (in >> terms of computer work) to walking 3 times one sequence ? > > Well, I guess there's the overhead of wrapping it in multiple seqs, > but the logic calculations will be the same regardless of which method > is used. > >> And nevertheless, if I insist, it's not really because there *could* >> be a performance problem (though I guess there will, but only >> benchmark would tell), but rather because the essence of the problem >> seems to be needing a simple reduction with early break capability, >> and no more :-) > > Well, I kinda disagree here. It seems to me that this: > > (defn interesting? [pixels c] > (> c (count (take c (filter in-interval? pixels > I can't but agree that it is less verbose. But I maintain (and then will let you 'cause I'm on holidays from right after this last email :-) that the initial problem calls for a modified reduce :-) > Is more straightforward than: > > (defn interesting? [pixels c] > (reduce (fn [counter pixel] (if (in-interval? pixel) (inc counter) > counter)) > 0 > pixels > (partial < c))) > > - James > > > --~--~-~--~~~---~--~~ 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: breaking early from a "tight loop"
Hi, 2009/6/14 CuppoJava : > > I actually really do like the reduce with early exit abstraction. > Because ultimately, that's what the question is. It's a reduce with > optimization. > > However, I feel that Laurence's reduce is a little too specific. The > early exit condition is very likely to *not* depend on the reduce > accumulator, but rather on some intermediate calculation in the reduce > function. > > It is possible to write something like this. But some people might be > concerned with how idiomatic this is. > > (my_reduce (fn [a b c] (if bla-bla (break))) initial_value collection) Yes, I suggested a similar alternative in my email also: "Another way to implement the new version of reduce would be by having the 4th parameter be an explicit "early-return value", and let the "do we return early ?" test be part of the reduction function ?" which is similar to what you say, while maybe a little bit more general (in the sense it does not introduce a symbol), and also maybe a little bit easier for implementing my_reduce : (my_reduce (fn [a b c] (if bla-bla :early-break)) initial_value collection :early-break) > > where (break) exits the immediate surrounding reduce. > > > --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---