Re: Get digits of a number

2013-01-19 Thread David Brown
Qiu Xiafei qiuxia...@gmail.com writes:

 (defn num-digits
   [num]
   (loop [n num res []]
     (if (zero? n)
       res
       (recur (long (/ n 10)) (cons (mod n 10) res)

How about  (quot n 10)  instead of (long (/ n 10))?  No sense in the
extra step.

David

-- 
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: if-let/when-let

2013-01-04 Thread David Brown

On Thu, Jan 03, 2013 at 11:14:30PM -0800, Evan Mezeske wrote:


Wouldn't it be more accurately named if-and-let if it supported that?  E.g.
(if (and x y z) ...).


I can see regular if-let being useful with more than one form, just
using the last value for the conditional.

   (if-let [a expr, b expr] ii ee)

could become

   (let [a expr, b expr] (if a ii ee))

Often, it is useful to have several intermediate results in a let:

   (if-let [subpart (complex-to-compute ...)
part (other-expr subpart ... subpart)]
 ...)

David


On Thursday, January 3, 2013 10:24:57 PM UTC-8, Edward Tsech wrote:

   Hey guys,

   if-let and when-let macros support only 2 forms in binding vector:

   (if-let [x 1 y 2]
 ...)
   java.lang.IllegalArgumentExcepdtion: if-let requires exactly 2 forms
   in binding vector(NO_SOURCE_FILE:1)

   Why doesn't if-let support any even amount of binding forms as let
   does?

   e.g.
   (if-let [x 1 y 2 z 3]
 (+ x y z)
 0) ; = 6

   (if-let [x 1 y nil z 3]
 (+ x y z)
 0) ; = 0

   Thanks!

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


Re: if-let/when-let

2013-01-04 Thread David Brown

On Fri, Jan 04, 2013 at 08:58:40AM +0100, Tassilo Horn wrote:


At least in my experience, it usually matters a lot which form actually
evaluated to nil.  But it's easy to write a macro `if-let-all' or so,
which would expand into

 (let [x 1 y nil z 3]
   (if (and x y z)
 (+ x y z)
 0))

if you really feel a need for it.


Seems like it's be a lot more useful to expand that to:

  (let [x 1]
(if x
  (let [y nil]
(if y
  (let [z nil]
(if z (+ x y z)
  else-clause))
  else-clause))
else-clause))

With maybe a fn thrown in to avoid repeating the else-clause.  This
allows constructs where successive values need to be computed, that
depend on the previous, and if we get a nil, we need to stop.

It's especially useful when interfacing with Java code with things
that really like to return nil on errors, and raise exceptions if you
pass the nil to the next step.

David

--
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: Dependency management

2010-01-22 Thread David Brown

On Thu, Jan 21, 2010 at 10:23:10PM -0800, Richard Newman wrote:

I'm somewhat swayed by Leiningen because it makes doing some things 
easy (uberjar! starting a REPL! neat!), at the cost of making other 
things (such as managing dependencies myself) more frustrating. 
However, if it wasn't for all the people blindly deleting their Ant 
build scripts, I would be sticking with my Ant workflow for another 
few months. I don't think Lein is quite targeted at users like me.*


For one project, I have a JNI that needs to be built as part of it.  I
tried converting this to Maven, and once I realized that I needed
numerous fake subprojects to work around Maven's rigid flow model, I
ended up going back to ant.

I ended up making a fairly general ant script that I can drop into any
project and build java/JNI/clojure source as needed.  If anyone is
interested, the code is at
http://github.com/d3zd3z/webweight

The build.xml is at the top, and the support files are under 'etc'.

David

--
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: how to create instance of java class that is internal of other?

2010-01-17 Thread David Brown

On Sat, Jan 16, 2010 at 03:30:49PM -0800, Sergey wrote:


But how?:)


Use a '$' character to delimit the internal class.

  ... (:import com.google.template.soy.SoyFileSet$Builder) ...

  ... (new SoyFileSet$Builder) ...

That's the real class name.  It's fairly easy to figure this out by
looking at the names of the class files that the Java compiler
generates.

David
-- 
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: Language similarities

2010-01-01 Thread David Brown
On Fri, Jan 01, 2010 at 12:31:16PM -0500, Mike Meyer wrote:
On Fri, 1 Jan 2010 13:45:43 -0300
Angel Java Lopez ajlopez2...@gmail.com wrote:

 I would like to add Ada exception management. I don't know if there were
 previous work on the field. Any info? I worked with Algol, but I don't
 remember if something like exceptions was present those days. Any early Lisp
 exception management?

Try/Catch were add to MacLisp in 1972, because the previous error
handling facilities (ERR/ERRSET) were being abused to get that
behavior. This predates the formation of the Ada working group by a
couple of years.

I don't think I've ever seen any cross references between any of the
Lisp documentation and any of the Ada documentation.  The Ada
rationale only references a couple of obscure papers about exceptions.
Perhaps they didn't want to scare people by mentioning where they got
the idea.

I guess another concept that wasn't really accepted until a
mainstream language started using it.

David

-- 
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: NPE in reify.

2009-12-29 Thread David Brown
On Tue, Dec 29, 2009 at 01:58:45PM -0500, Rich Hickey wrote:

(type (Small))
:user/Small

You can use this keyword type tag for multimethod dispatch.

I did eventually figure this out.

I am a bit confused as to why you would want to reify a deftype. You
can reify protocols, however.

I need to make something that defines it's own Comparable, and I also
want a custom printer for it.  Once I figured out that the multimethod
dispatch in the printer uses type, and I can just use that on the
deftype name, it got much easier.

Hopefully there isn't too painful a transition period moving from
multimethods to protocols.

Thanks,
David

-- 
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: Why use monads

2009-12-28 Thread David Brown
On Mon, Dec 28, 2009 at 12:44:31PM +0100, Konrad Hinsen wrote:

 This fact is realized even in haskell community:
 http://lambda-the-ultimate.org/node/2749#comment-41078

That article is about monad transformers, not monads themselves. BTW,
monad transformers are simpler in Clojure than they are in Haskell
(they are ordinary functions), so some arguments in that thread don't
apply to the same degree.

Well, they still end up mostly as just functions in Haskell, with lots
of extra wrapping and unwrapping to get the type system to work.

The advantage in Haskell, is that 'lift' and friends (liftIO) figure
out at compile time how many invocations are needed to get to the
right monad.

My biggest complaint about the monad transformers was that they make
the program design fragile.  Having to make small changes to what
monads were used tended to have a pervasive effect on the rest of the
code.  Much of this had to do with type declarations, so this might
not be as much of an issue with Clojure.

David

-- 
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: Access to nested static classes

2009-12-28 Thread David Brown
On Mon, Dec 28, 2009 at 02:50:59PM -0800, Mark Tomko wrote:
This, however, does not work:

(ns org.tomko.konkordans.analysis
  (:import
(org.tomko.konkordans NestedStatics)))

(def foo NestedStatics$LevelOne$LevelTwo/NO)

The class is called NestedStatics$LevelOne$LevelTwo, so you would have
to import that if you wanted to use it.  As far as the JVM is
concerned, NestedStatics, NestedStatics$LevelOne and
NestedStatics$LevelOne$LevelTwo are just three independent classes.

Java added nested classes, but didn't really add them to the JVM.  It
just makes longer class names using the '$'.

It's probably safe to rely on this behavior, since there is plenty of
code that depends upon it working this way.

David

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


NPE in reify.

2009-12-23 Thread David Brown
The following generates an NPE during compilation:

   (deftype Small [])
   (defn wrap []
 (reify Small))

Obviously, my real use has more interfaces I implement, but this shows
the problem.

My problem is that I need to override 'print-method', which is using
defmulti off of 'type' of it's argument.  I guess I could also
implement IMeta and provide a tag as well.  But, the workaround I've
been using is to create an empty interface in Java, which reify is
happy to implement.

David

-- 
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: Parenthesis Inference

2009-12-20 Thread David Brown
On Sun, Dec 20, 2009 at 02:30:58PM -0500, Luc Préfontaine wrote:

People bought HP calculators not for the Postfix notation but for all
the others things it offered at the time...

Some of us _still_ only buy HP calculators because of the postfix
notation.  Oh, the other things are nice, too.

David

-- 
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: Code arrangement for understandability

2009-12-10 Thread David Brown
On Thu, Dec 10, 2009 at 09:26:07AM -0500, Graham Fawcett wrote:

(let [x 1
  _ (f x)
  y (+ x 2)
  _ (g y)]
  ...)

What do people in general think of this style?  I remember using this
trick a lot with O'Caml, and I've certainly used it a few times in
Clojure, but something feels icky about it.

Where it's most useful, though is with stuff like this:

   (let [x ...
 y ...
_ (prn y is y)
...]
 ...)

I have found I sometimes find something like:

   (let [x ...
 x (... x ...)
x (... x ...)
x (... x ...)]
 x)

easier to write, even if it is just how I write it the first time, and
then later change it to something looking more like function
application.  Sometimes, I've found the let-chain is easier to modify
in the future.

I guess, realizing it's still not imperative (necessarily), it
shouldn't bother me as much.

David

-- 
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: Code arrangement for understandability

2009-12-10 Thread David Brown
On Thu, Dec 10, 2009 at 09:13:33AM -0800, samppi wrote:

notation before, and it is fine. For my tastes, however, I think that
it repeats the symbol (in this case, 'x) too much. Sometimes it may be
the best way, but usually I would instead use -, -, and/or letfn.

The problem I have using - and - is that I often find inconsistency
as to which argument the value should be placed at.

David

-- 
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: Trouble implementing Dijkstra algorithm in Clojure

2009-12-08 Thread David Brown
On Tue, Dec 08, 2009 at 03:22:47PM -0800, ataggart wrote:

I would be very surprised if getting the first element from a sorted-
set wasn't ~O(1).

As has been mentioned, it probably isn't if the set is a tree.

But, also, usually, in addition to getting the first element, we also
are going to want a set without the first element to represent the
rest of the data.

Both a sorted-set and a priority-queue are probably O(log n) for the
first/rest operation, but the constant factor is likely to be quite
different.

David

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

2009-12-04 Thread David Brown
On Sat, Dec 05, 2009 at 01:38:36AM +0300, Ivan Sagalaev wrote:
Cliff Wells wrote:
 I am
 unable to see why someone shouldn't be able to receive a signed PDF via
 email and achieve a similar level of confidence that the signor was
 legitimate.

BTW Canonical does exactly that[1]. I've just recently signed their CCA
which consisted of downloading a PDF from the site and sending it back
to them with the words like I agree with this.

It's going to depend a lot on who is interpreting the laws and what
decisions they make.  I've done contributor agreements via scanned
documents and via fax.  I don't think I've yet actually mailed one
(although that may change if I contribute something to Clojure).

David

-- 
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: Space usage of lazy seqs

2009-12-03 Thread David Brown
On Wed, Dec 02, 2009 at 08:18:33PM -0800, Dave M wrote:

On Dec 2, 9:09 pm, David Brown cloj...@davidb.org wrote:
...
 If you're running JDK 6, you can run the virtualvm, or jconsole to get
 a better handle on the memory usage, and even dig into what it might
 used for.

Google does not return useful references to a tool called virtualvm;
perhaps you mean VisualVM (jvisualvm)?

Yes, that is indeed what I meant to type.

David

-- 
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: Space usage of lazy seqs

2009-12-02 Thread David Brown
On Wed, Dec 02, 2009 at 02:01:36PM -0800, Johann Hibschman wrote:

There is a qualitative difference between the runs, though. I can run
test-split-3 five times in a row, all with similar times, without
having the java process size get bigger than 0.6 GB. When I run any of
the others, the size quickly balloons up to something more like 8.5
GB.

How much memory do you have on your machine.  A recent Sun JVM on a
machine with a bunch of memory will consider it to be a server
machine.  It will set the heap max to 1/4 of total physical memory
(which suggests you might have 16GB of RAM).

You can tune the max with -Xmx1G for example, to limit it to one GB.

The actual interaction with the GC can be hard to predict, and Sun's
GC seems to like to sometimes use as much memory as it has been given.

If you're running JDK 6, you can run the virtualvm, or jconsole to get
a better handle on the memory usage, and even dig into what it might
used for.

David

-- 
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: ANN: Web application framework (beta)

2009-11-29 Thread David Brown
On Sun, Nov 29, 2009 at 11:09:38PM -0500, Jim Powers wrote:

Clearly what would be desired is portable continuations that can be loaded
on any machine and/or duplicated/replicated for failure cases.

All of the persistent classes in Clojure, including continuations
claim to implement Serializable.  Not sure how well it actually works,
but if implemented, it should be possible to send a closure even to a
different machine.

David

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


'sync' call in writeClassFile

2009-11-28 Thread David Brown
This commit:

 commit 5577a47a390782d7ab911c2e3c4c8be1b0341aa8
 Author: Rich Hickey richhic...@gmail.com
 Date:   Sat Feb 7 14:46:56 2009 +
 
 added sync to writeClassFile

Adds a 'sync()' call to the class file write.  On systems where the
underlying fsync() call causes a flush all the way to disk (Linux)
this makes AOT compilation about an order of magnitude slower,
especially given the large number of functions in typical clojure
code.

Anyone know the history behind this?  It makes AOT compilation on
Linux about 5x slower than on OSX.

The call to sync() takes longer than the compilation did.  It would be
a win to just clean all of the class files and rebuild after a crash.

The current behavior makes working off of battery on a laptop
unworkable, since it keeps the harddisk from spinning down.

These are just the output of the compiler, easily regenerated.

David

-- 
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: Space leak with lazy sequences.

2009-11-27 Thread David Brown
On Fri, Nov 27, 2009 at 01:52:05PM +0200, Miron Brezuleanu wrote:

not sure if it works here, but what about adapting advice from Stuart
Halloway's Programming Clojure (pages 159-160, 'Losing your head') and
use a function returning a sequence instead of a 'bound by let' name
(the actual advice in the book is to use functions returning sequences
instead of vars holding the head)? This is basically a delayed
evaluation trick similar to your workaround with atoms.

That seems to work as long as you aren't using the sequence as part of
IO where the sequence is consumed in the middle.  I think the atom
trick is needed for my case as far as I can tell.

David

-- 
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: Space leak with lazy sequences.

2009-11-26 Thread David Brown
On Thu, Nov 26, 2009 at 04:00:34PM -0800, David Brown wrote:

For now, I'll do without the with-open, since in this particular case,
errors are going to be fairly fatal anyway.

BTW, I still haven't been able to figure out how to write this
function without hanging onto the collection across the call to
'write-mapping'.

Any ideas?

;;
(ns leak1)
(import '[java.io FileOutputStream BufferedOutputStream DataOutputStream])

(defn make-name [ _])
(defn make-tmp-name [ _])
(defn store-properties [ _])
(defn write-mapping [ _])
(defn get-codec [ _])
(defn raise[ _])
(def error nil)

;;; The generated code creates a 'fn' class for the body of the
;;; with-open.  This class binds several of the names, including
;;; 'coll', which it keeps through the lifetime of the function.
(defn- store-index-file
   [index idx props coll]
   (let [path (make-name index idx)
 tmp-path (make-tmp-name path)
 fos (FileOutputStream. tmp-path)
 bos (BufferedOutputStream. fos)]
 (with-open [dos (DataOutputStream. bos)]
   (store-properties dos (assoc props :version 1.0))
   (write-mapping dos (get-codec index) coll)
   (.flush bos)
   ;; Calls fsync to make sure data gets written to disk.
   (.force (.getChannel fos) true))
 (when-not (.renameTo tmp-path path)
   (raise error
  (str Unable to rename pool index file: tmp-path  to  
 path)
;;

-- 
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: Space leak with lazy sequences.

2009-11-26 Thread David Brown
On Thu, Nov 26, 2009 at 05:05:17PM -0800, David Brown wrote:
On Thu, Nov 26, 2009 at 04:00:34PM -0800, David Brown wrote:

For now, I'll do without the with-open, since in this particular case,
errors are going to be fairly fatal anyway.

BTW, I still haven't been able to figure out how to write this
function without hanging onto the collection across the call to
'write-mapping'.

Ugh, I have found a very ugly hack that works.

It seems that the compiler only nulls out locals before a call in the
tail position, even if earlier calls don't reference the value any
more.

So, I went down in my call-chain to the first function that uses the
sequence directly (in a doseq), and do something like this:

   (let [real-coll @coll]
 (swap! coll (constantly nil))
 (doseq [item real-coll] ...))

I just have to wrap the collection in an atom up where I create it,
and make sure I never keep a reference to it around.

David

-- 
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: Recursions under lazy-seq - how does it work?

2009-11-25 Thread David Brown
On Wed, Nov 25, 2009 at 09:40:44AM -0800, Gabi wrote:

Very interesting indeed. I am not sure I understand completely, but by
intuition I presume that the recursive call actually creates a new
heap allocated LazySeq (with the function definition inside) . So is
there some help from the compiler for this? How does the recursive
call suddenly transfers into a call to a LazySeq object ?

Actually, the compiler doesn't really do anything.  lazy-seq is a
macro, a very short one at that.  I suggest making sure you have
cloure.contrib.repl-utils available, and just try:

   (source lazy-seq)

and see for yourselves.  The only real compiler magic is that it sets
the metadata {:once true} on the function it creates which makes for a
bit better code for functions that will only ever be called once.

But yeah,

   (defmacro lazy-seq
 ...
 [ body]
 (list 'new 'clojure.lang.LazySeq (list* '#^{:once true} fn* [] body)))

That's it.  The neat thing is that you or I can also write macros that
do this kind of thing.  It's one of the things that makes Lisp so
powerful.

David

-- 
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 User Survey, preparation for 1.1

2009-11-24 Thread David Brown
On Tue, Nov 24, 2009 at 01:04:57AM -0800, Meikel Brandmeyer wrote:
Hi,

On Nov 24, 9:44 am, bOR_ boris.sch...@gmail.com wrote:

 Can we get an option 'leiningen' at how do you get clojure?

I think this is basically Maven/Ivy, no?

Leiningen includes, within it's own Jar, a particular version of the
clojure snapshot, which is why it currently only compiles against the
one built into it.  It uses Maven to download other dependencies, but
not Clojure itself.

David

-- 
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: roll call of production use?

2009-11-23 Thread David Brown
On Mon, Nov 23, 2009 at 03:00:16PM -0800, Raoul Duke wrote:

i'd be interested to hear who has successfully used clojure in
production. i know of some, as some folks have been vocal; any other
interesting-but-so-far-silent uses people'd be willing to fess up
about?

I've thrown together a small clojure program to present an internal
dashboard of active projects and states and stuff.  Having the JVM was
invaluable, since I could easily make postgreSQL queries as well as
use JGit to walk the history of a git repository.

I've mentioned this before, but http://github.com/d3zd3z/webweight
is a small program I wrote to learn compojure.

One significant part is that I've written an org.davidb.contrib.html
and xml that wrap around the same data structure used by clojure.xml.
It allows for easier construction of html/xml in code:

   (html/table :border 1
 (html/tr
   (html/td :valign top Cell) ..))

I also wrote an html/xml emitter that uses ones from the standard Java
libraries, since the one in clojure.xml doesn't actually generate
valid xml.

The other interesting part of webweight is that the build.xml and the
ivy and files under etc are sufficient to build most Clojure projects.
It's similar to the idea behind Leiningen, but it will also build Java
and native code into the project as well.

The production webpage is internal, and has a lot more data on it, but
I've captured and scrubbed a snapshot
http://www.davidb.org/dashboard/sample.html

I was able to throw the whole thing together in just a couple of days
using Clojure.  I haven't really felt this productive writing code
since using Common Lisp.

David

-- 
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 User Survey, preparation for 1.1

2009-11-23 Thread David Brown
On Mon, Nov 23, 2009 at 09:55:46PM +, the.stuart.sie...@gmail.com wrote:

Since the form only lets me answer one answer for each, but reality is
much more complicated.

How do you get Clojure? *

Download release
Github
Maven or Ivy

I primarily use the latest development snapshot that I pull down with
Maven/Ivy.

But, I also keep a git workspace and bounce between master and new.

As far as chunked sequences, I started using clojure after they were
already in place, so I don't really have anything to compare it with.

David

-- 
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: leiningen - a Clojure build tool

2009-11-22 Thread David Brown
On Sun, Nov 22, 2009 at 01:05:43AM -0800, bOR_ wrote:

elif [ ${1: -4} = .clj ]; then
# Small hack to use lein to start clojure scripts
java -cp $CLASSPATH clojure.main $1

How about
elif [ ${1: -4} = .clj ]; then
# Small hack to use lein to start clojure scripts
java -cp $CLASSPATH clojure.main $@

So you can even pass arguments to the script.

BTW, the leiningen.core invocation at the end should also be $@ so
that arguments with spaces don't get expanded into multiple arguments.

If you add arguments to the 'repl' case, then you can run scripts
using that as well.

David

-- 
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: leiningen - a Clojure build tool

2009-11-22 Thread David Brown
On Sun, Nov 22, 2009 at 07:14:33AM -0800, bOR_ wrote:

What is the normal way to let Leiningen know about local jars? I am
using brics automaton in one of my projects, and that jar is only
downloadable after confirming the bsd licence (http://www.brics.dk/
automaton/), so I have it locally on my disk, but it isn't in clojars
or mvnrepositiory.com.

When the maven fails to find the package, it will spew out
instructions on how to install it into your local maven cache.
Something like:

   mvn install:install-file -DgroupId=org.domain -DartifactId=package
 -Dversion=1.2.3 -Dpackaging=jar
 -Dfile=path/to/file.jar

But, on one line.

Having to agree with a BSD license is a bit strange.

David

-- 
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: Oh, yeah, transients are fast!

2009-11-22 Thread David Brown
On Sun, Nov 22, 2009 at 11:45:46AM -0500, John Harrop wrote:

Nothing so serious as a hang, though, and at least I can do basic things in
my IDE without reaching for the frelling manual every two minutes to look up
some key-combination :)

I suspect both models are going to be important.  I feel the same way
you do when I'm running an IDE rather than vim.

Oddly enough, I've found myself most productive with a repl in it's
own window, and a short script (below) in user.clj to let me specify a
namespace to test.

I put this in a 'repl' directory that I only add to my classpath for
the repl script.

David

(println Running user startup)
(use 'clojure.contrib.repl-utils)
(use 'clojure.contrib.str-utils)
(use 'clojure.contrib.java-utils)
(use 'clojure.contrib.def)
(use 'clojure.contrib.ns-utils)
(use 'clojure.contrib.test-is)
(use 'clojure.contrib.sql)
(use 'clojure.stacktrace)

(set! *warn-on-reflection* true)

;;; The NS that we are testing/working on.
;;; This can be given through the java property work-ns, e.g.
;;;   ./run.sh -Dwork-ns=org.davidb.chunk-file
(def *work-ns*
   (symbol
 (or (System/getProperty work-ns)
 'org.davidb.foo)))

;;; A testing NS.
(def *test-ns*
   (symbol
 (or (System/getProperty test-ns)
 (symbol
   (re-sub #[^\.]+$ #(str test- %)
   (name *work-ns*))

; (use *work-ns*)
(defn l [] (binding [*warn-on-reflection* true]
  (use *work-ns* :reload)))
(defn t []
   (binding [*warn-on-reflection* true]
 (require *test-ns* :reload)
 (run-tests *test-ns*)))
(defn i [] (in-ns *work-ns*))

; Load the User's test-user.clj if present.
(try (load /test-user)
   (catch java.io.FileNotFoundException e
 (println No test-user.clj found in classpath.)))

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


How to make this a non-reflecting call?

2009-11-22 Thread David Brown
java.nio.channels.FileChannel contains some .write methods:

[27] write : int (ByteBuffer)
[28] write : int (ByteBuffer,long)
[29] write : long (ByteBuffer[])
[30] write : long (ByteBuffer[],int,int)

I have an array of ByteBufers, but I can't figure out how to call #29
without it being a reflecting call.  Giving a type of #^objects
doesn't seem to help.

   (defn foo [#^FileChannel chan, bufs]
 (.write chan (to-array bufs)))

gives a reflection warning.

Any ideas?

-- 
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: How to make this a non-reflecting call?

2009-11-22 Thread David Brown
On Sun, Nov 22, 2009 at 01:00:51PM -0500, John Harrop wrote:
On Sun, Nov 22, 2009 at 12:55 PM, David Brown cloj...@davidb.org wrote:

 java.nio.channels.FileChannel contains some .write methods:

 [27] write : int (ByteBuffer)
 [28] write : int (ByteBuffer,long)
 [29] write : long (ByteBuffer[])
 [30] write : long (ByteBuffer[],int,int)

 I have an array of ByteBufers, but I can't figure out how to call #29
 without it being a reflecting call.  Giving a type of #^objects
 doesn't seem to help.

   (defn foo [#^FileChannel chan, bufs]
 (.write chan (to-array bufs)))

 gives a reflection warning.

 Any ideas?

Try #^[LByteBuffer;

That doesn't parse.

I did get it to work with reflection, by using (into-array ByteBuffer
bufs) instead of to-array.  That way I at least get the right array
type, even if the compiler can't figure it out.

Any idea what kind of performance hit this actually ends up being?

David

-- 
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: tree-shaking a jarred Clojure app?

2009-11-21 Thread David Brown
On Fri, Nov 20, 2009 at 06:37:18PM +, Jim Downing wrote:

I might have misunderstood, but isn't the problem the same as in Java;
you can't know from a static analysis which classes are going to be
loaded?

Except that Clojure will load all of them so it can bind them to the
vars in each namespace.  Java code is usually much less dynamic, and
makes some static analysis a lot easier.

JVMs are pretty good about not loading classes until they are used, so
I think the real problem is that the init code for each namespace
loads all of the classes before it does anything.  If that could be
delayed, I suspect most of the startup delay would go away.  The trick
is figuring out how to do this without adding yet another level of
indirection to vars.

David

-- 
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: Weird Java Interop Behaviour

2009-11-21 Thread David Brown
On Fri, Nov 20, 2009 at 03:54:45PM -0800, Mike Hinchey wrote:
It's the . special form that makes the difference.  In (. System
(getProperty)), the dot interprets System as a class and looks for a static
method (at read/compile time).  With (identity System), System resolves to a
value, a Class object, returned by identity, then your outside dot looks for
a getProperty instance method on that object(fallback to reflection, which
fails) - it's like writing System.class.getProperty in java.  There is no
syntax for clojure to lookup a static method on a dynamically resolved class
object because that is inherently reflection - dot is not about reflection,
though it will do it as a last resort.

So, if I've acquired a dynamically resolved class and want to invoke a
static method, is my only choice to manually use reflection?

David

-- 
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: tree-shaking a jarred Clojure app?

2009-11-21 Thread David Brown
On Sat, Nov 21, 2009 at 08:42:26PM -0500, John Harrop wrote:

Are you talking about binding things like String.class to vars referenced by
symbols like String?

Not just String.class, every single class referenced by a given
namespace will be loaded, and most of them instantiated before a
single line of my code runs.  It's why:

   $ time ant
   ... (no ant file, it just fails)
   real 0m0.155s

   $ time clj -e '(System/exit 0)'
   real 0m0.960s

is so drastically different.  Compiling this:

   (ns foo (:gen-class)) (defn -main [])

and running

   $ time java -cp classes:clojure.jar foo
   real 0m0.749s

still loads and instantiates every single function defined in
core.clj.

David

-- 
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: tree-shaking a jarred Clojure app?

2009-11-21 Thread David Brown
On Sat, Nov 21, 2009 at 11:14:52PM -0500, John Harrop wrote:

1 second instead of 1/6 of a second. Yeah, like users will notice that
difference in startup times. :)

I'm not actually complaining, but I do notice every single time I fire
up a REPL.  The more code that you have, the longer it takes.  It's
basically completely thwarting the JVM's attempt to lazily load
classes.

I have the same complaint about JRuby and Scala.  Scala cheats a
little, and their REPL prints a prompt before actually loading the
classes.

Honestly, I think it's a reasonable penalty to pay for a system that
is both dynamic and very fast.

David

-- 
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.xml/parse of XHTML yields a 503 on the DTD

2009-11-18 Thread David Brown
On Tue, Nov 17, 2009 at 10:12:19AM -0800, David Brown wrote:
On Tue, Nov 17, 2009 at 08:03:59AM -0800, pkw wrote:

I'm having this same problem.  Did you find a way around it?
I want to try changing the User-Agent, but I can't figure out
how to do that.

I suspect that the Sax parser by default is configured to not allow
fetching of the DTD over the net.

I worked around this by replacing the URL in the DOCTYPE declaration
with a file one and fetching the files myself.  But, admittedly
that's not a good solution.

BTW, the emitter in clojure.xml doesn't produce valid xml, either,
unless your xml is very simple.  It certainly doesn't work round-trip.

David

-- 
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: Proposal: Extend behavior of hash-map

2009-11-18 Thread David Brown
On Tue, Nov 17, 2009 at 03:24:46PM -0800, Richard Newman wrote:

Baby, bathwater. Making a persistent map out of a Java map is
expensive. Not everything that implements Map is concrete; e.g.,
spending several seconds making a local persistent Clojure map out of
a distributed hash table proxy, just to get a value, would cause
programmers to drop down to Java to avoid this pointless restriction.
Why bother?

I wonder if there's a use for a lazy 'bean' call, then.  Lots of
things use bean properties to do things that can be quite expensive.

David

-- 
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.xml/parse of XHTML yields a 503 on the DTD

2009-11-17 Thread David Brown
On Tue, Nov 17, 2009 at 08:03:59AM -0800, pkw wrote:

I'm having this same problem.  Did you find a way around it?
I want to try changing the User-Agent, but I can't figure out
how to do that.

I suspect that the Sax parser by default is configured to not allow
fetching of the DTD over the net.

I worked around this by replacing the URL in the DOCTYPE declaration
with a file one and fetching the files myself.  But, admittedly
that's not a good solution.

David

-- 
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: idomatic sudoku?

2009-11-15 Thread David Brown
On Sun, Nov 15, 2009 at 09:43:38PM +0100, B Smith-Mannschott wrote:
On Sun, Oct 11, 2009 at 22:12, Matt Wilson m...@problemattic.net wrote:

 The only hassle with a map is that iterating over it (in my case, with
 a `for`) turns it into a list of [key value], which makes it a pain to
 turn back into a map once you're done. The magical incantation for
 round-tripping turns out to be:

 (apply hash-map (apply concat seq-of-pairs))

Why not just

   (into {} seq-of-pairs)

David

-- 
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: Datatypes and Protocols - early experience program

2009-11-15 Thread David Brown
On Sun, Nov 15, 2009 at 04:20:19PM -0500, John Harrop wrote:

That's weird. It's not documented anywhere on the site. And it seems to hang
the REPL:

user= nil #!foo

and nothing. Enter doesn't print nil and a fresh user= prompt as it
should and nothing else apparently works either. The REPL is either wedged
or interpreting everything as comment from then on.

Weirdly enough, ; hangs the REPL likewise.

How's the data getting to the REPL?  jline, or ide?  I'm using rlwrap
at the console, and netierh seems to cause problems.  However, #! eats
everything, and doesn't prompt again, but does after the next line.
The ; prints a new prompt, so they are definitely treated differently.

David

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

2009-11-14 Thread David Brown
 On Jan 21, 4:39 pm, Frank ffai...@gmail.com wrote:

  I am interested in trying to use Clojure to develop web-based
  applications.  Can someone point me to any Clojure libraries that have
  been written that I can use.  Thanks.

I spent a couple of days this week using Compojure both in anger, and
for fun.  The anger stuff isn't source-available, but my fun project
is:

   http://github.com/d3zd3z/webweight

There is (hopefully) a live version at:

   http://www.davidb.org/wlog?

The app itself probably isn't that interesting itself, since it
generates the reports for my weight management program.

Part of my goal was to be well integrated with Maven, but also have
decent interactive use.

   - setup-repl.sh uses Maven to download the dependencies and put them
 in a place that 'run.sh' is expecting them.  Combined with the
 user.clj I wrote, it allows me to do things like:

   ./run.sh -Dwork-ns=org.davidb.webweight.daily

 and get a REPL where (l) will reload this namespace, (t) will load
 one with the name of org.davidb.webweight.test_daily and run tests
 on it (there aren't tests in this code yet), and (i) will switch
 to the dev namespace.  It doesn't reload sub-required namespaces,
 so isn't perfect, but still quite useful.

   - mvn compile should work with the maven-clojure-plugin.  It'll also
 package a jar file.

   - mvn assembly:assembly will make a jarfile containing the
 dependents.  There's a org.davidb.webweight.main that can run it
 directly.

All in all, it's a fairly quick framework to setup.

My github page also has my patches to compojure to build it under
Maven.  The json library is from Tim Dysinger's repo:
git://github.com/dysinger/clojure-json.git.  I just installed these
locally.

The in anger project connects to a PostgreSQL database and interacts
with a backend auto-build system.

David

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

2009-11-12 Thread David Brown
On Thu, Nov 12, 2009 at 10:21:32AM +1100, John Ky wrote:

Does anyone know why if the first character in my *.clj file is '#', then
when I open it in VIM, ClojureVIM fails to recognise it as a Clojure file?

Vim runs the type detectors that examine the file before the ones
based on filename.  The vimclojure name-based autodetector uses
'setfiletype' which only sets the filetype if it hasn't been detected
already.

The simplest fix is to change the 'setfiletype' in the
ftdetect/clojure.vim file to 'filetype'.  This tells it to force the
filetype to clojure when it ends in '.clj' no matter what it was
detected as.

You can also make line 2 of the file be something like:
; vim: set filetype=clojure :

and just override it on an individual basis.

David

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


vimclojure indentation problem.

2009-11-12 Thread David Brown
Speaking of vimclojure, has anyone else encountered situations where
the vimclojure indent decides that the indentation of top-level
constructs should be two spaces over?  I haven't been able to figure
out a pattern, and sometimes I can even fix it by just scrolling up
and back.

David

-- 
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: Problem w/ daemon threads

2009-11-12 Thread David Brown
On Thu, Nov 12, 2009 at 07:50:31AM -0800, Sean Devlin wrote:

(defn daemon
  Creates a new daemon thread and sets runnable to f
  [f]
  (let [t (Thread. f)]
(do
  (.setDaemon t true)
  (.start t)
  t)))

And I tried calling

user=(daemon #(println foo))

I get the thread back, but it does not appear to execute.  I've tried
this on OSX and XP.  Does anyone know what I'm doing wrong?

I tried this on Linux, and prints foo once, which is what I would
expect.

If you want it to be period, though, you'll need to use something like
Executors/newSingleThreadScheduledExecutor to create a scheduler for
it.

I tried writing a periodic scheduler using agents (and a ref to manage
state).  Turns out that getting shutdown working robustly is actually
fairly tricky.  I recommend just using the scheduler available in
Java.

David

-- 
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: Using agents and blocking I/O.

2009-11-10 Thread David Brown
On Tue, Nov 10, 2009 at 07:41:41AM -0800, pmf wrote:

 This thing could easily create a lazy sequence, in fact, the code
 would look a lot like the code for seque, with just a separation of
 the writer from the reader.  I'll have to think about it to make sure
 that it can be used safely.

You might want to look at the (recently added) fill-queue (in
clojure.contrib.seq-utils), which provides a lazy seq that is filled
by another thread and blocks if readers consume faster than the queue
is filled; maybe your problem fits into this mechanism.

Well, almost.  Except that it would create a future that I really
don't have any use for.  Last night, I posted very similar code to do
the same kind of thing with an agent (I have since fixed the exception
handling in the agent so it terminates the queue so the reader will
get an exception rather than just hang).

With fill-queue, send-queued, and seque all looking nearly identical,
I wonder if we're missing how this should be abstracted.

I did learn, though from reading it that seque stops short if the
computation runs ahead enough to fill up the queue.  I'm not quite
sure what this would be useful for.

(import '(java.util.concurrent BlockingQueue LinkedBlockingQueue))
(defn send-queued
   Dispatch blocking action to agent.  The state of the agent will be
   set to the value of:
   (apply action-fn state-of-agent enqueue args)
   The agent should call enqueue for each item to return to the caller
   of send-queued.  send-queued returns a lazy sequence of the items the
   agent passes to enqueue (in order).  The agent may enqueue 'n' items
   before blocking on its call to enqueue.
   [a n f  args]
   (let [#^BlockingQueue q (LinkedBlockingQueue. (int n))
 NIL (Object.) ;nil sentinel since LBQ doesn't support nils
 enqueue (fn [x]
   (.put q (if (nil? x) NIL x)))
 action (fn [state1]
  (try
(let [state2 (apply f state1 enqueue args)]
  (.put q q) ; q itself is eos sentinel
  state2)
(catch Exception e
  (.put q q)
  (throw e
 drain (fn drain []
 (lazy-seq
   (let [x (.take q)]
 (if (identical? x q) ;q itself is eos sentinel
   (do @a nil)  ;touch agent just to propagate errors
   (cons (if (identical? x NIL) nil x) (drain))]
 (send-off a action)
 (drain)))

-- 
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: Better documentation and error messages are needed for the ns macro

2009-11-10 Thread David Brown
On Tue, Nov 10, 2009 at 09:08:31PM -0500, John Harrop wrote:

In case anyone was wondering, apparently it wants

(ns foo.bar.baz
  (:use [clojure.contrib.core :only (seqable?)]))

(and thus violates the usual clojure rule of using vectors rather than lists
for groupings that are not invocations -- that is, function calls, macro
calls, or special form calls).

You can use vectors for everything other than the outside parens, if
you'd like.  They just need to be sequences.  I'm guessing people
usually use parens on the :use, because it at least looks like an
invocation (and is similar to the (use ...) call).  I've seen the
:only followed by a vector.

David

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


Iterative collections.

2009-11-09 Thread David Brown

Given the recent talk about iter and how most of the expressions can
be done easily with sequences and map.  I however, have found that map
often makes these difficult to read because the names are up front in
the function and the arguments follow this.

So, I threw together the following macro that allows map of an
anonymous function to be written more in the style of 'let'.  If it
isn't obvious, the bindings can be destructuring.

(defmacro let-map
   Evaluates the exprs, each of which should return a sequence.  These
   are bound to the binding forms for subsequent calls, and the results of
   the last expression in body are collected into a sequence.
   [bindings  body]
   (assert (vector? bindings))
   (assert (even? (count bindings)))
   (let [pairs (partition 2 bindings)
 bs (map first pairs)
 exprs (map second pairs)]
 `(map (fn [...@bs] ~...@body) ~...@exprs)))

For evaluating to cause side-effects, you can do (dorun (let-map
...)), but I may also write a 'let-seq' that implements this using
recur to avoid the allocation of the sequence.

   (let-map [x [31 41 59 26]
 y (iterate inc 1)]
 (+ x y))

Probably not that interesting in the simple case.

David

--~--~-~--~~~---~--~~
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: equivalent to Haskell's group function

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 04:49:16PM +, Emeka wrote:

What is the gain of using lazy-seq here? Why can't we go without laziness?

   - The lazy version doesn't consume stack per length of the sequence.
   - The lazy version works with unbounded sequences.

For short sequences it probably doesn't matter much, but these are
also probably the cases where performance isn't as much of a concern.

David

--~--~-~--~~~---~--~~
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: Iterative collections.

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 09:07:31AM -0800, pmf wrote:

On Nov 9, 5:39 pm, David Brown cloj...@davidb.org wrote:

    (let-map [x [31 41 59 26]
              y (iterate inc 1)]
      (+ x y))

 Probably not that interesting in the simple case.

How is this different from using for? It's also lazy and supports
destructuring.

(for [x [31 41 59 26]
  y (iterate inc 1)]
  (+ x y))

And gives very different results.  'for' iterates over it's sequences
in a nested fasion.  For your particular example, it will return the
sequence from (+ 31 1) (+ 31 2) and so on, and never get to the second
element of the first vector.

'let-map' walks through the sequences together, like 'map', hence the
name.  The given 'let-map' example returns a sequence of 4 elements.

David

--~--~-~--~~~---~--~~
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: How to convert java Complex type to Clojure type?

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 11:42:32PM +0100, Michael Jaaka wrote:

How to convert HashMapString, String to Clojure map, sorted-map,
tree-map

   (into {} hm)
or
   (into (sorted-map) hm)

where hm is the hash map.

You can also just use the hash map like you would a Clojure map, but
it might change on you, since it is mutable.

David

--~--~-~--~~~---~--~~
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: Consistency of the API

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 08:41:25PM -0500, John Harrop wrote:

In the meantime, the main thing still missing from Clojure is a convenient
queue. Lists and vectors both add and remove efficiently only at one end,
and at the same end for add and remove in both cases. Doubly-linked lists
can't be made persistent without massive problems, but laziness has its own
issues:

Perhaps the GHC Data.Sequence library could be ported.  It's based on
2-3 finger trees, and allows efficient adding and removal from either
end of the sequence.

Depending on use behavior, you can also make a decent lazy queue just
out a two lists, where you reverse and append whenever the source side
fills up.

David

--~--~-~--~~~---~--~~
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: Consistency of the API

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 05:53:28PM -0800, Mark Engelberg wrote:

On Mon, Nov 9, 2009 at 5:41 PM, John Harrop jharrop...@gmail.com wrote:
 In the meantime, the main thing still missing from Clojure is a convenient
 queue.

What's wrong with clojure.lang.PersistentQueue?

The only clojure constructor I could find for this is in
clojure.contrib.accumulators.  But, once you have the empty one
'clojure.lang.PersistentQueue/EMPTY' you can use it pretty well with
the rest of the language.

Perhaps 'empty-queue' should be moved into core?

David

--~--~-~--~~~---~--~~
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: Consistency of the API

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 05:54:36PM -0800, David Brown wrote:

Depending on use behavior, you can also make a decent lazy queue just
out a two lists, where you reverse and append whenever the source side
fills up.

Ok, this is what PersistentQueue is, except without the reverse and
append, so it actually performs well.

David

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



Using agents and blocking I/O.

2009-11-09 Thread David Brown

I'm trying to get a better grasp of how Agents are intended to be
used, so let me give an example scenario.

Let's say I have some thing that keeps track of the state of some I/O
entity, let's say some kind of file-based storage.  There is state
associated with the entity.  It's important that only one thread be
able to read or write from this storage at a time, since the state has
to match what the external store's state is (say it's a cache or
something).

Write requests seems like a perfect match for agents, since they will
be serialized and will happen asynchronously.  But, what about reads.
The reader needs to be able to get the result back from the read, how
to do this.

I can think of a few ways:

   - The reader passes in an atom to hold the result.  After issuing
 the request, awaits for the agent to process the request, and then
 retrieves the answer from the agent.

   - It could use a BlockingQueue of some type to wait for the answer.

In both cases, the reads run completely synchronously, waiting for
their answer, and really the whole thing isn't really any better than
just using locks.

Or, should I rethink the whole thing, and try to represent my entire
problem reactively?  The essentially means converting my entire
problem in to continuation-passing style, and giving some of the
continuations to agents.  Possible, but very pervasive.

Any suggestions?

Thanks,
David

--~--~-~--~~~---~--~~
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: Using agents and blocking I/O.

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 08:28:43PM -0800, David Brown wrote:

In both cases, the reads run completely synchronously, waiting for
their answer, and really the whole thing isn't really any better than
just using locks.

I guess a deeper concern is that there seems to only be a single call
in the entire Clojure concurrency system: 'await'.

One very useful extension GHC adds to STM is the 'retry' call, which
causes the transaction to retry, but it blocks until something else
modifies one of the refs that it has read.  It allows any arbitrary
concurrency to be implemented, since now a thread can wait for a
result, for example.

Should I just be less afraid of using the Java concurrency classes?

David

--~--~-~--~~~---~--~~
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: Vector manipulation problem, possible function for a solution.

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 05:19:41PM -0800, Don wrote:

I am having a problem with vectors.  It seems there should be a
function for this however I am not sure.

I have a vector a [ [2 3] [4 5] [6 7] ]

And I want to be able to get [2 3 4 5 6 7]

There's a flatten in clojure.contrib.seq-utils that does this.  Well,
it gives you a sequence when you can put back into a vector if you
need.

David

--~--~-~--~~~---~--~~
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: Using agents and blocking I/O.

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 09:42:28PM -0800, Mark Engelberg wrote:

But let's say the agent is responsible some enormous database, and
it's impractical for the in-memory state to hold all the information
that readers might find useful.  In this case, I think you're right
that the basic agent functionality doesn't map well to this without
some additional work.  It seems like you would need to create a read
message which essentially is a function that reads the relevant data
from the database and stores it in some sort of future-like stateful
entity that will block when you deref it until it has been filled by
the agent.

Ok.  So, it's the existence of this future-like entity that blocks
upon deref until filled is indeed somewhat missing.  It's not
particularly difficult to implement.

This thing could easily create a lazy sequence, in fact, the code
would look a lot like the code for seque, with just a separation of
the writer from the reader.  I'll have to think about it to make sure
that it can be used safely.

Making it a full queue unstead of just an event handles the common
case where I will have a sequence of reads to make.

Thanks,
David

--~--~-~--~~~---~--~~
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: Using agents and blocking I/O.

2009-11-09 Thread David Brown

On Mon, Nov 09, 2009 at 10:07:41PM -0800, David Brown wrote:
On Mon, Nov 09, 2009 at 09:42:28PM -0800, Mark Engelberg wrote:
But let's say the agent is responsible some enormous database, and
it's impractical for the in-memory state to hold all the information
that readers might find useful.  In this case, I think you're right
that the basic agent functionality doesn't map well to this without
some additional work.  It seems like you would need to create a read
message which essentially is a function that reads the relevant data
from the database and stores it in some sort of future-like stateful
entity that will block when you deref it until it has been filled by
the agent.

Making it a full queue unstead of just an event handles the common
case where I will have a sequence of reads to make.

Ok, here's my first attempt.  It seems to work.  It's basically like
send-off, except that it wants a queue size, and it returns a lazy
sequence.  It passes an extra argument to the agent function that the
agent should call with each item it wishes to queue.  This is largely
modelled after seque from core.

(import '(java.util.concurrent BlockingQueue LinkedBlockingQueue))
(defn send-queued
   Dispatch blocking action to agent.  The state of the agent will be
   set to the value of:
   (apply action-fn state-of-agent enqueue args)
   The agent should call enqueue for each item to return to the caller
   of send-queued.  send-queued returns a lazy sequence of the items the
   agent passes to enqueue (in order).  The agent may enqueue 'n' items
   before blocking on its call to enqueue.
   [a n f  args]
   (let [#^BlockingQueue q (LinkedBlockingQueue. (int n))
 NIL (Object.) ;nil sentinel since LBQ doesn't support nils
 enqueue (fn [x]
   (.put q (if (nil? x) NIL x)))
 action (fn [state1]
  (let [state2 (apply f state1 enqueue args)]
(.put q q) ; q itself is eos sentinel
state2))
 drain (fn drain []
 (lazy-seq
   (let [x (.take q)]
 (if (identical? x q) ;q itself is eos sentinel
   (do @a nil)  ;touch agent just to propagate errors
   (cons (if (identical? x NIL) nil x) (drain))]
 (send-off a action)
 (drain)))

David

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



Avoiding reflection/hinting with byte-array.

2009-11-07 Thread David Brown

I can't figure out how to avoid reflection, in the 'update' method of
MessageDigest.  It is overloaded on a single argument with either
'byte', 'byte[]', or 'java.nio.ByteBuffer'.

   (import '(java.security MessageDigest))
   (set! *warn-on-reflection* true)

The compiler didn't seem to like a tag that wasn't actually a class
name:

   (def byte-array-class
 (class (make-array Byte/TYPE 0)))

   ;; Unable to resolve classname: byte-array-class
   (defn update1
 [#^MessageDigest md #^{:tag byte-array-class} item]
 (.update md item))

And it seems to have no effect if I expand it as the tag:

   ;; call to update can't be resolved.
   (defn update2
 [#^MessageDigest md #^{:tag (class (make-array Byte/TYPE 0))} item]
 (.update md item))

In this particular case, I was able to work around the issue one of
two ways, basically by using a different type.

   (defn workaround
 [#^MessageDigest md item]
 (.update md item 0 (count item)))

   (defn workaround2
 [#^MessageDigest md item]
 (.update md (java.nio.ByteBuffer/wrap item)))

Any ideas?  BTW, my real use case is in a defmethod, where I handle
several other types for the update.

Thanks,
David

--~--~-~--~~~---~--~~
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: Avoiding reflection/hinting with byte-array.

2009-11-07 Thread David Brown

On Sat, Nov 07, 2009 at 11:48:32AM -0500, Chouser wrote:

This should work:

(defn update1 [#^MessageDigest md, #^bytes item]
  (.update md item))

This does seem to work, thanks.

Any reason that 'doubles' is also defined as an array cast function,
but 'bytes' is not?

David

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