Re: super-lazy-seq

2009-06-14 Thread Wrexsoul

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

2009-06-14 Thread Stephen C. Gilardi


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?

2009-06-14 Thread CuppoJava

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

2009-06-14 Thread vmargioulas

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?

2009-06-14 Thread evandi

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

2009-06-14 Thread Emeka
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

2009-06-14 Thread James Reeves

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

2009-06-14 Thread Emeka
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

2009-06-14 Thread peg

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

2009-06-14 Thread Wrexsoul

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

2009-06-14 Thread Parth



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

2009-06-14 Thread tmountain

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

2009-06-14 Thread James Reeves

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

2009-06-14 Thread James Reeves

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

2009-06-14 Thread tmountain

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

2009-06-14 Thread James Reeves

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

2009-06-14 Thread markgunnels

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

2009-06-14 Thread Jarkko Oranen

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"

2009-06-14 Thread Sudish Joseph

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"

2009-06-14 Thread Max Suica

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"

2009-06-14 Thread Max Suica


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

2009-06-14 Thread Max Suica

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"

2009-06-14 Thread Max Suica

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"

2009-06-14 Thread Sudish Joseph

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"

2009-06-14 Thread Sudish Joseph

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-06-14 Thread Laurent PETIT

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"

2009-06-14 Thread Laurent PETIT

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