Re: Duplicated keys in maps

2009-10-11 Thread John Harrop
On Sun, Oct 11, 2009 at 8:55 PM, Angel Java Lopez ajlopez2...@gmail.comwrote:

 Hi people!

 I just discovered that maps support duplicated keys:

 user= {:a 1 :b 2 :a 3}
 {:a 1, :b 2, :a 3}

 It was not clear to me, from documentation. I presumed that maps are like
 dictionaries.

 What is the rationale behind this behaviour?


I doubt there is one. I suspect it's a bug.

= (assoc {:a 1 :b 2} :a 3)
{:a 3, :b 2}

= (type {:a 1 :b 2 :a 3})
clojure.lang.PersistentArrayMap

= (type (assoc {:a 1 :b 2} :a 3))
clojure.lang.PersistentArrayMap

Looks like there's a constructor that breaks the PersistentArrayMap (and
Map) contract and is used when building one from a literal. Associng the
key-value pairs one by one into an empty map is probably the only way to fix
it. Detecting duplicate keys in map literals at read time is NOT enough:

=(def x :a)
= (def y :b)
= (def z :c)
= {x 1 y 2 z 3}
{:a 1, :b 2, :c 3}
= (def z :a)
= {x 1 y 2 z 3}
{:a 1, :b 2, :a 3}

Runtime-variable keys can be duplicates without it being evident at read
time, or even predictable at all (equivalent to the halting problem). There
are only two behaviors that seem reasonable here, duplicate keys produce a
runtime exception or duplicate keys quietly overwrite earlier ones. The
latter is achieved by the an array literal is a shorthand for (assoc (assoc
(assoc ... (assoc {} k1 v1) ... k2 v2) k3 v3) k4 v4) semantics, whether
implemented that way or in some more-efficient way (transients? special
constructor?) and both have situations where they might be desirable. I'd
argue for the former, it throws an exception, on the basis that explicit
associng (or (reduce conj {} [[k1 v1] [k2 v2] [k3 v3]]) or (hash-map k1 v1
k2 v2 k3 v3)) can be used to achieve the latter effect where desired, and
most usually duplicate keys would represent an error. Duplicate keys
detected at read time (same keyword, quoted symbol/form, string or numeric
literal, or var) could of course be reported as errors at the compilation
stage.

= (reduce conj {} [[:a 1] [:b 2] [:c 3]])
{:c 3, :b 2, :a 1}
= (reduce conj {} [[:a 1] [:b 2] [:a 3]])
{:b 2, :a 3}
= (reduce conj {} [[x 1] [y 2] [z 3]])
{:b 2, :a 3}
= (hash-map x 1 y 2 z 3)
{:a 3, :b 2}

--~--~-~--~~~---~--~~
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: Is there a standard function transforming a map's vals

2009-10-11 Thread John Harrop
On Sun, Oct 11, 2009 at 3:17 PM, Daniel Werner 
daniel.d.wer...@googlemail.com wrote:

 On Oct 11, 6:02 am, samppi rbysam...@gmail.com wrote:
  Oops, you're right; I was thinking about something else. And I have
  another mistake in my function too—I meant:
 
(defn transform-map [f a-map]
  (into {} (map #(vector (key %) (f (val %))) a-map)))
 
  It's unfortunate that it's not in any standard library yet. I've used
  this function in every single Clojure program that I've written. Ah,
  well.

 Konrad Hinsen's generic functor multimethod seems to do exactly what
 you want:

 user= (use 'clojure.contrib.generic.functor)
 nil
 user= (fmap inc {:a 4, :b 3})
 {:a 5, :b 4}

 Actually it is not limited to maps:

 user= (fmap inc [4 3])
 [5 4]

 It's just too easy to miss beautiful and useful gems like this in the
 depths of clojure.contrib.


Agreed. That's why I may create a kind of mind map of that library (and
throw in clojure.core) that can find functions by, well, function. So all
the stuff for manipulating maps can be found, or all the stuff for file I/O,
etc.

--~--~-~--~~~---~--~~
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: Agents for managing threads

2009-10-10 Thread John Harrop
Here is a quickie library for abstracting this:
(defn make-actor [f period-in-ms  initial-state]
  (agent (into [f period-in-ms false] initial-state)))

(defmacro actor
  Creates and returns a new, initially-sleeping actor with the specified
period, initial parameter values, and code to execute.
  [period-in-ms initial-bindings  body]
  `(let [p# ~period-in-ms]
 (make-actor
   (fn [~@(take-nth 2 initial-bindings)] ~...@body)
   p#
   ~@(take-nth 2 (rest initial-bindings)

(defn- actor-act [state]
  (when (nth state 2)
(apply (first state) (drop 3 state))
(Thread/sleep (second state))
(send-off *agent* actor-act))
  state)

(defn- actor-start [state]
  (send-off *agent* actor-act)
  (into [(first state) (second state) true] (drop 3 state)))

(defn- actor-stop [state]
  (into [(first state) (second state) false] (drop 3 state)))

(defn- actor-change-state [state new-state]
  (into [(first state) (second state) (nth state 2)] new-state))

(defn start-actor
  Wakes up an actor -- starts it periodically executing its body.
  [actor]
  (send-off actor actor-start))

(defn stop-actor
  Puts an actor to sleep again.
  [actor]
  (send-off actor actor-stop))

(defn change-actor-state
  Changes an actor's parameter list.
  [actor  new-state]
  (send-off actor actor-change-state new-state))


Test at the REPL with these:

= (def y (actor 1000 [x 1 y 1] (println (+ (* x 10) y

= (start-actor y)

11 should start repeating to stdout.

= (change-actor-state y 2 2)

It should stop repeating 11 and start repeating 22.

= (stop-actor y)

Output should halt.

(start-actor y)

Output should resume.

(stop-actor y)

Output should halt.

(change-actor-state y 4 7)

No immediate effect.

(start-actor y)

Output should resume, but printing 47 instead of 22.

(stop-actor y)

Output should stop.

Note that the (actor ...) macro resembles a fn form in use (though
destructuring won't work). In the body, the parameters can be referred to by
name to use them. When it is called, it is with an ordered list of values to
bind to those parameters. The (change-actor-state ...) function is followed
by the actor and then such a parameter list, so in the example above since x
was the first parameter (change-actor-state y 4 7) binds 4 to x on
subsequent executions of the actor body.

Under the hood, it's exactly as described: the actor body is wrapped in a fn
with those parameter names and the actor is invoked periodically with an
argument list, which is replaced by change-actor-state. The actor itself is
an agent wrapping a vector with the function, period, awake flag, and
current parameters.

Trivial additions: creating a (defactor name ...) macro that functions like
(def name (actor ...)); adding a change-actor-period function.

More interesting, but fairly easy: have the function take one extra
parameter, the previous invocation's return value, and specify an initial
value for it in (actor ...). This enables the function to maintain a mutable
cell of sorts.

Nontrivial: add destructuring.

--~--~-~--~~~---~--~~
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: Agents for managing threads

2009-10-10 Thread John Harrop
On Sat, Oct 10, 2009 at 5:52 PM, Raoul Duke rao...@gmail.com wrote:


  The actor itself is
  an agent wrapping a vector with the function, period, awake flag, and
  current parameters.

 will actors actually do the queued function w/in a reasonable
 timeframe? i don't think there are any guarantees of it so if one is
 hoping to get really nicely periodic behaviour... just curious because
 i'd thought of using agents for periodic stuff, too.


In practice, they seem to.

--~--~-~--~~~---~--~~
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: Another defmult VS defn query

2009-10-08 Thread John Harrop
On Thu, Oct 8, 2009 at 10:25 AM, Robert Stehwien rstehw...@gmail.comwrote:

 (defn mv2 [from to]
   (let [f (if (= (class from) File) from (File. from))
 t (if (= (class to) File) from (File. to))]
 (println transformed to File)))


ITYM

t (if (= (class to) File) to (File. to))]

for that third line.

I have a function as-file I would use for this:

(defn as-file [file-or-name]
  (if (instance? file-or-name java.io.File)
file-or-name
(File. file-or-name)))

Then the above simplifies to:

(let [f (as-file from)
  t (as-tile to)]

--~--~-~--~~~---~--~~
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: What does this error mean?

2009-10-08 Thread John Harrop
On Thu, Oct 8, 2009 at 11:09 AM, Mark Tomko mjt0...@gmail.com wrote:

 Can you give some more context?


The pesky thing about that particular error is that there IS no more
context; it fingers no specific line of code, function definition, or
whatever as culprit.

--~--~-~--~~~---~--~~
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: Agents for managing threads

2009-10-08 Thread John Harrop
On Thu, Oct 8, 2009 at 1:06 PM, Laurent PETIT laurent.pe...@gmail.comwrote:

 So I don't think you need this message-queue at all (or maybe I haven't
 understood what it is or I'm mislead by its name), send directly your order
 to the agent as what you want to change in its state.


You might be able to do better than that, and dispense entirely with the
separate polling thread.

Break the state involved in the polling into a variable and a constant part.
Constant might be a pocket on a socket on a port, variable a
polling/non-polling flag and some other stuff. Wrap the latter in a
structure such as a list or a map and stuff it in an agent. Create some
functions that close over the former, some to change the agent state and one
to do the polling.

The polling one should check the are-we-polling flag of the state, return
the state if we're not polling, and otherwise poll, sleep however-long, and
(send-off *agent* poll), then return the state. The one to turn on polling
also needs to end with (send-off *agent* poll) and then return the modified
version of the state (with the we're-polling flag assoc'd true). The effect
of all this should be:

If the agent is told to start polling, it gets enqueued with a poll
send-off, and immediately after the last send returns and sets the new agent
state, the poll function is then executed. Every however long this repeats.

If a state change is sent to a polling agent, it probably arrives during the
poll function's sleep. This state change message is thus queued by the agent
ahead of the poll message it sends itself at the end of the sleep. So the
state change is done next, then the poll, and for that poll the state change
should be in effect.

If the state change included stop-polling, then since the poll function
checks the we're-polling flag and aborts if we're not polling, that next
poll is a no-op; in particular, the agent does not send itself another poll
message, and will be completely quiescent until sent a start-polling
message.

--~--~-~--~~~---~--~~
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: Agents for managing threads

2009-10-08 Thread John Harrop
On Thu, Oct 8, 2009 at 7:49 PM, John Harrop jharrop...@gmail.com wrote:

 You might be able to do better than that, and dispense entirely with the
 separate polling thread.


Confirmed:

(def x (agent {:polling false :message foo}))

(defn poll [m]
  (when (:polling m)
(prn (:message m))
(Thread/sleep 1000)
(send-off *agent* poll))
  m)

(defn set-message [m mess]
  (assoc m :message mess))

(defn start [m]
  (send-off *agent* poll)
  (assoc m :polling true))

(defn stop [m]
  (assoc m :polling false))

(send-off x start)

The message foo should start repeating in the standard-output monitor
window of your IDE.

(send-off x set-message bar)

The message bar should start repeating in the standard-output monitor
window of your IDE, in place of foo.

(send-off x stop)

The output should stop, and look like this:

foo
foo
foo
foo
bar
bar
bar

with possibly different numbers of repetitions. Seems to indicate that this
strategy works beautifully for a periodically-repeating behavior that
accepts state-change messages, including start and stop signals.

--~--~-~--~~~---~--~~
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: immutable defs?

2009-10-07 Thread John Harrop
On Tue, Oct 6, 2009 at 9:14 PM, Stephen C. Gilardi squee...@mac.com wrote:

 `(do (set-validator! (defvar ~name ~init) #{~init}) (var ~name)))


Cute hack. Won't work if init is false or nil, though, unless the validator
does not trigger on the initial assignment of the value.

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

2009-10-05 Thread John Harrop
On Sun, Oct 4, 2009 at 4:41 PM, samppi rbysam...@gmail.com wrote:


 I want to do this:

  (defn a ...)
  (cache a) ; or (cache #'a) or (cache 'a); it doesn't matter to me

 ...instead of this:

  (def a (memoize (fn ...)))

 That way, it separates the concern of what a does from the
 optimization I'm doing on it. Now, I'm kind of stuck; how should I do
 it?

  (defn cache
Replaces the function that the given variable refers to
with a memoizing version of it.
[fn-var]
(??? fn-var (memoize @fn-var)))


Why not use a macro?

(defmacro cache
  Replaces the function that the given variable refers to
   with a memoizing version of it.
  [fn-var-name]
  `(def ~fn-var-name (memoize ~fn-var-name)))

--~--~-~--~~~---~--~~
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: apply for macros?

2009-10-05 Thread John Harrop
On Mon, Oct 5, 2009 at 2:38 PM, Meikel Brandmeyer m...@kotka.de wrote:

 Hi,

 Am 05.10.2009 um 19:29 schrieb cody koeninger:

  Here we have the smell! You cannot define functions with a function.
 You have to use a macro!


 I am not clear on what you mean by this.  From a user's point of view,
 what is the difference between defining a function, and interning a
 var with a fn object as its value?

 user (defn define-function [name] (intern *ns* name (fn [] (str
 called a generated function:  name
 #'user/define-function
 user (some-function)
 ; Evaluation aborted.
 user (define-function 'some-function)
 #'user/some-function
 user (some-function)
 called a generated function: some-function

 Or is your point just that #'fn is a macro?


 I stand corrected.


I'd argue that you can define a function within a function, but that
interning a var within a function is a smell, and doing it with a constant,
rather than argument-supplied or computed, name, in a function or in a
macro, is a stench (e.g. (defn foo [x y z] (defn bar ... )))

--~--~-~--~~~---~--~~
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: Agent send-off: ~20k/s

2009-10-05 Thread John Harrop
On Mon, Oct 5, 2009 at 11:51 AM, MarkSwanson mark.swanson...@gmail.comwrote:

 On Oct 5, 2:45 am, ngocdaothanh ngocdaoth...@gmail.com wrote:
  I think it is not spawn about 20K agents / second, it is 20K message
  passings / second. The number is about that of Erlang.

 As Clojure uses a thread pool for agents I agree 'spawn' was the wrong
 word. Thanks for the correction.


Some confusion here may also be from the subject line. It mentions send-off,
which actually can spawn unlimited numbers of new threads. Regular send
doesn't, using a fixed thread pool instead.

--~--~-~--~~~---~--~~
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: apply for macros?

2009-10-04 Thread John Harrop
On Sat, Oct 3, 2009 at 6:50 PM, b2m b2monl...@googlemail.com wrote:

  What macros do y'all have that you want to apply things to?
 (defn init-funs [name  levels]
   (do
(apply-macro create-department-struct name levels)
(apply-macro create-process-department name levels)
nil))

 A call like
 (init-funs company1 level1 level2)
 will result in
 (defstruct company1-department :name :head :level1 :level2)
 and so on.

 So I need macros for the benefit of individual strucs and functions
 for every company, and I need something like apply to pass
 parameters from the inital function to the macros. This is working by
 using (eval (apply-macro... as described in a previous posting in this
 thread. It would be nice to have a solution without eval. But maybe my
 attempt of writing code that writes code is too enthusiastic.


Not really. But since you're automating generation of deffoos (in this
example, defstructs) you can, and should, use macros all the way down. I.e.
init-funs can, and should, be a macro above and it can then just be:

(defmacro init-funs [name  levels]
  `(do
(create-department-struct ~name ~...@levels)
(create-process-department ~name ~...@levels)
nil))

or similarly as the case may be.

If you need to be creating these things dynamically, with information only
available at runtime, defstruct is probably the wrong tool for the job, or
the only struct member should be :name, and the levels at least should just
be ordinary map keys (not struct keys); then you can dispense with init-funs
entirely, and replace the call currently used to get a new instance of the
struct with a call that given a name, figures out the appropriate levels
(from a name to level-name-list hashmap you maintain at runtime) and
initializes a structmap with the :name struct-key set appropriately and also
empty lists for each level-name key appropriate for that name.

Or something like that.

--~--~-~--~~~---~--~~
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: apply for macros?

2009-10-03 Thread John Harrop
In the specific cases of and and or, I made utility functions that do
non-short-circuiting and and or for use with apply and a stream of
boolean data. (Not sure which implementation is more efficient though: a
version that returns its argument with one argument, punts to the
appropriate macro with two, and uses recur with more than two; a version
similar to that that uses reduce with more than two; or a higher-level
(every? identity args) / (some? identity args). The latter are clearly more
elegant, but speed is a concern with something that might be used often.)

What macros do y'all have that you want to apply things to? Most likely
what you need is to make a version that's a function, if you can live
without some deferred/selective evaluation of arguments type feature (like
the short-circuiting of and).

--~--~-~--~~~---~--~~
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 using shell-out in Windows command prompt

2009-10-01 Thread John Harrop
On Thu, Oct 1, 2009 at 1:39 PM, Nick Day nicke...@gmail.com wrote:


 Hey,

 I've just been trying to run a couple of simple commands using shell-
 out (e.g. (sh dir)) in a repl in Windows command prompt, but am
 running up against errors of the type

 java.io.IOException: Cannot run program dir: CreateProcess error=2,
 The system cannot find the file specified (NO_SOURCE_FILE:16)


Shell built-in commands. If you're directly launching an external process
from the JVM, there's no dir executable to find. You need to invoke it in
the command interpreter instead of directly. I'm unsure how to do that.

--~--~-~--~~~---~--~~
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: Citing clojure

2009-10-01 Thread John Harrop
On Thu, Oct 1, 2009 at 3:42 PM, Dragan Djuric draga...@gmail.com wrote:


 I usualy cite Rich's conference paper and Stuart's book.

 @conference{hickey2008clojure,
  title={{The Clojure programming language}},
  author={Hickey, R.},
  booktitle={Proceedings of the 2008 symposium on Dynamic languages},
  year={2008},
  organization={ACM New York, NY, USA}
 }


Eeeuw. What a non-Lispy syntax. What is that, anyway?

--~--~-~--~~~---~--~~
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: server-socket on exit event

2009-10-01 Thread John Harrop
On Thu, Oct 1, 2009 at 4:02 PM, Roger Gilliar ro...@gilliar.de wrote:

 Am 01.10.2009 um 21:28 schrieb ngocdaothanh:
  Roger, your code is not event based.
 What do you mean by not event based ?


He means he wants automatic notification if a connection is dropped.

I'm not sure TCP/IP has a native facility for that.

What most chat type programs, multiplayer games, and suchlike do is send a
periodic ping from server to each connected client, which as part of the
chat protocol the client is supposed to acknowledge. If a client stops
responding for more than a few ping-intervals, it's assumed to have
disconnected or otherwise become unreachable.

This method has the advantage of being entirely under the control of the
application layer, and the further advantage of also working with UDP (which
is crucial in the multiplayer games case at least).

--~--~-~--~~~---~--~~
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: ClojureCLR installation?

2009-09-30 Thread John Harrop
On Tue, Sep 29, 2009 at 7:21 PM, David Miller dmiller2...@gmail.com wrote:

 Mono:
   - One BigDecimal implementation away from getting serious about
 this.


Why doesn't Mono have a BigDecimal analogue? It shouldn't, in principle, be
difficult to create an open-source-friendly implementation backed by GMP.

--~--~-~--~~~---~--~~
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 understand macro in clojure?

2009-09-29 Thread John Harrop
On Mon, Sep 28, 2009 at 5:23 AM, Jarkko Oranen chous...@gmail.com wrote:

 What happens is, when you call (mfloat + 1 2) the macro evaluates ('+
 (float 1) (float 2)), ie. it calls the *symbol* + with parameters 1.0
 and 2.0. Symbols, when used as functions, look themselves up in
 whatever associative thing you give them as the first parameter, OR
 return the second parameter in case of lookup failure. So, ('+ 1.0
 2.0) evaluates to 2.0, which is the macro expansion. and as 2.0
 evaluated is 2.0, it is the actual result.


Very sneaky. Why is invoking a symbol returning the second argument even
when the first is not an associative thing at all? It should probably return
the second argument (defaulting to nil) on not-found but not on genuine
errors. A ClassCastException java.lang.Float cannot be cast to
clojure.core.IAssoc (or whatever) would have been more informative in this
case.

--~--~-~--~~~---~--~~
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: Mocking?

2009-09-29 Thread John Harrop
On Mon, Sep 28, 2009 at 9:20 AM, Laurent PETIT laurent.pe...@gmail.comwrote:

 2009/9/28 C. Florian Ebeling florian.ebel...@gmail.com

  In Java I'd just have an interface
  with two implementations, and bootstrap the tests with a different
  implementation, in clojure I guess I'd do something like:
  (in-ns `some.thing)
  (defn foo [] nil)
  or something?

 That would consitute a root binding because of the 'defn, but you need
 a dynamic rebinding. This is what you can use:

 (binding [existing-function (fn [a b] ...)]
   ;; your tests here
)


 But as soon as your application becomes smart enough to do things in
 parallel (e.g. create and send an e-mail in a separate thread), just using
 dynamic binding in tests may not be enough, still the binding will not be
 seen by default by other threads.


Does fixtures get around that? Perhaps by saving the root binding,
redef'ing it, and later restoring it?

--~--~-~--~~~---~--~~
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: Mocking?

2009-09-27 Thread John Harrop
On Sun, Sep 27, 2009 at 8:06 PM, Stuart Sierra
the.stuart.sie...@gmail.comwrote:

 On Sep 27, 12:55 am, Mark Derricutt m...@talios.com wrote:
  How are people handling mocking/stubbing in clojure?  Google finds me
 some
  old posts about a called? function/macro as part of test-is which looks
 like
  it'd do what I need but I can't seem to find any trace of it under
  clojure/clojure-contrib trunk.

 clojure.contrib.test-is (now clojure.test) has a fixtures feature.
 It doesn't do mocking itself, but provides a mechanism for temporarily
 rebinding vars in your tests.


Isn't (binding [foo bar] ...) already such a mechanism? Or does the
fixtures feature let you specify such a binding for a whole group of tests
obviating the need to repeat the binding form in multiple test functions,
and perhaps let mutable state carry forward through multiple tests instead
of being rebound (and thus reset) after each one?

(And why does the gmail interface seem designed to encourage users to
top-post?)

--~--~-~--~~~---~--~~
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: Macros, namespaces, and lexical scope

2009-09-25 Thread John Harrop
On Fri, Sep 25, 2009 at 4:49 PM, Constantine Vetoshev gepar...@gmail.comwrote:

 (let [f1 #(inc %)]
  (defmacro m1 [x]
`(~f1 ~x)))

 (m1 12)
 = No message.
  [Thrown class java.lang.ExceptionInInitializerError]

 The equivalent works in Common Lisp (Allegro CL and SBCL):

 (let ((f1 (lambda (y) (1+ y
  (defmacro m1 (x)
`(funcall ,f1 ,x)))

 (m1 12)
 = 13

 Thoughts on either of these brain teasers?


I don't think you can use things like defmacro in a let. Macros are used at
macroexpansion time and I don't think a let's bindings will exist yet. So
you probably need something like

(defmacro m1 [x]
  (let [f1 #(inc %)]
`(~f1 ~x)))

instead.

--~--~-~--~~~---~--~~
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: Macros, namespaces, and lexical scope

2009-09-25 Thread John Harrop
On Fri, Sep 25, 2009 at 8:48 PM, Constantine Vetoshev gepar...@gmail.comwrote:


 On Sep 25, 6:02 pm, John Harrop jharrop...@gmail.com wrote:
  I don't think you can use things like defmacro in a let.

 This works:

 (let [y 10]
  (defmacro m1 []
`(list ~y)))

 (m1) =
 (10)


Well, that's weirdly inconsistent. It shouldn't work just *some* of the
time. Either it should work, or it shouldn't work. According to the language
semantics, it should work if let bindings wrapping def forms are in effect
during any side effects of the def form, and should fail otherwise.

Anyone knowledgeable about clojure internals have any idea why it would work
sometimes, but only sometimes?

Did you get a detail message or stack trace from the exception you saw?

--~--~-~--~~~---~--~~
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 running clojure.test

2009-09-23 Thread John Harrop
On Wed, Sep 23, 2009 at 12:29 PM, MarkSwanson mark.swanson...@gmail.comwrote:

 Environment: vimclojure-2.1.2. clojure from git as of a few days ago.

 Running the tests in a plain REPL from the command line worked
 perfectly!
 -=* THANKS GUYS !!! *=-

 I wasn't expecting this at all. I thought the REPL in vimclojure
 actually supported stdout because this works:
  (def a abc)
 #'user/a
  a
 abc
  (println a)
 abc
 nil

 I have noticed that mouse paste operations into the vimclojure repl
 fail (the pasted text is truncated after a certain number of
 characters).
 These seem to be indications that stdin/stdout is not handled
 perfectly by vimclojure...


I'm not surprised. In fact I am surprised that mouse paste operations work
at all in an editor that legacy. I've noticed that us NetBeans users have an
environment that just works, including mousing and pasting into the REPL as
well as stdout displaying correctly, while a quarter of the list traffic
here deals with problems configuring either emacs or vim, or quirky
post-configuration behavior from same. :)

Modern IDEs for the win?

But assuming you'd rather not change environments, I'd suggest not using
whatever crummy mouse and clipboard support has been retrofitted onto vim
and instead use your terminal emulator's paste that will present the pasted
text to vim as if it were being typed into vim. That should work however
long the pasted text is, unless the terminal emulator paste is equally
broken, which if it's xterm it shouldn't be, and otherwise you should
probably use xterm. :)

(No flames please. The above is offered as observations and a possible
workaround in the spirit of suggesting possible fixes so the O.P. can get on
with actually developing whatever they're developing with a minimum of fuss
and distractions.)

--~--~-~--~~~---~--~~
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: Getting REPL transcript

2009-09-23 Thread John Harrop
On Wed, Sep 23, 2009 at 1:05 PM, Fogus mefo...@gmail.com wrote:

 If you're running it with JLine, then the transcript is usually stored
 in ~/.jline-clojure.lang.Repl.history


Actually, that suggests a more general point: that we can have programmatic
access to the REPL's backlog if we modify the REPL process's Java code
somewhat. A simple example would be to make a repl.class that would provide
an interactive stdin/stdout repl but log everything to a ./repl.log file or
whatever. This could be used to obtain a text file with the interaction
history afterward, to massage, cut and paste from, etc. to one's heart's
content in a text editor. Even on MS-DOS, if anyone still uses such a
dinosaur. :)

--~--~-~--~~~---~--~~
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: question regarding agents

2009-09-23 Thread John Harrop
On Wed, Sep 23, 2009 at 4:18 PM, Roger Gilliar ro...@gilliar.de wrote:

 I have the following code:

 (defn handle-client [in out]
(binding [
*in* (reader in)
]
(with-connection db
(let [outstream (agent (writer out))]
(loop []
(let [xml (read-input)]
(if xml
(do

  (send-answers (parse outstream (makestr xml)))
(recur))
(info
 disconnected


 The problem is, that it doesn't work to assign an agent to the
 outstream. If I do, the content of the agent (the outstream in this
 case) is set to nil after it is passed to send-answers and all send-
 answers does is to store the agent in a struct.  Why that ?


Wrapping a mutable thing like an output stream in an agent seems dubious to
me.

Then you don't dereference it -- you pass the agent itself to parse as its
first argument, rather than the stream it wraps. That might not have been
what you intended.

Try just dropping the (agent ...) around (writer out).

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

2009-09-23 Thread John Harrop
On Wed, Sep 23, 2009 at 6:42 PM, Phil Hagelberg p...@hagelb.org wrote:

 What's going on here?


The exception is being transformed. Eval and just about anything using
closures -- just about any delayed evaluation, in other words -- wraps
exceptions in RuntimeException for some reason. Even if they already were
RuntimeExceptions (and InterruptedException isn't).

--~--~-~--~~~---~--~~
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: Namespace/class visibility in eval

2009-09-22 Thread John Harrop
On Tue, Sep 22, 2009 at 6:46 PM, Eric Tschetter eched...@gmail.com wrote:

 If I do just

 curl 'http://localhost:43034/1.0/cloj' -H 'content-type:
 application/clojure' -d '(json-str {:howdy [hi 1 2 3]})'

 I get this exception

 java.lang.Exception: Unable to resolve symbol: json-str in this
 context (NO_SOURCE_FILE:0)


Looks like only clojure.core is imported as far as read/eval is concerned.

Something like this

 curl -v 'http://localhost:43034/1.0/cloj' -H 'content-type:
 application/clojure' -d (require 'clojure.contrib.json.write)
 (json-str {:howdy [\hi\ 1 2 3]})

 Doesn't work because I'm only read/eval'ing one thing.


Wrap the require and json-str in a do.

Or, modify your original code so that what read operates on includes this
require. Something like:

(defroutes evallerificator
 (POST /1.0/cloj
   (eval (list
 `do
 `(require (quote clojure.contrib.json.write))
 (read (PushbackReader. (InputStreamReader. (request
:body)))
 (GET /
   (html [:h1 Hello World]))
 (ANY * (page-not-found)))

or, if that doesn't work (it proves to be read that does symbol
resolution),

(defroutes evallerificator
 (POST /1.0/cloj
   (eval (read-str (str
  (do (require 'clojure.contrib.json.write) 
  (slurp (PushbackReader. (InputStreamReader. (request
:body
  )
 (GET /
   (html [:h1 Hello World]))
 (ANY * (page-not-found)))

(untested!)

But, this looks like a gaping security hole. You're taking an HTTP POST
request body and eval'ing it. Someone will, sooner or later, try typing
(delete all the secret files) into the web form and clicking Send. Or
worse, something that will actually delete something or grant privilege.
Sending (doall (iterate inc 1)) will crash the server with OOME after a
lengthy 100%-cpu-use hang while it fills memory with consecutive Integer
objects, for a cheap and easy DoS attack. And so forth.

The last example shows that even vetting the incoming string for I/O is not
enough protection. (And the incoming string could sneak I/O in in numerous
ways; a lengthy computation could assemble a dynamic string equal to
with-open or InputStream and another equal to a file path (/etc/passwd
anyone?) and combine them. It might use symbol or read, then eval.
Blocking eval just makes them resort to cobbling together classnames and
method names from obfuscated fragments and then invoking Java reflection,
e.g. Class/forName. Maybe if you blocked every Java reflection-related class
name as well as read, eval, and the Clojure I/O forms -- but even then
someone can request an infinite seq be doall'd or similarly to cause some
amount of trouble, even if deleting files or creating a privileged account
on the server machine is placed out of their reach.)

--~--~-~--~~~---~--~~
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: Q: why doesn't this script terminate

2009-09-21 Thread John Harrop
On Mon, Sep 21, 2009 at 2:22 PM, Richard Newman holyg...@gmail.com wrote:


  But this script doesn't terminate. I have to press ctr-c to end this
  script. It seems that there a still some threads active. why ?

 http://www.mail-archive.com/clojure@googlegroups.com/msg13865.html


Your response was longer than

(shutdown-agents)

would have been.

Furthermore, in my experience almost no-one likes posts consisting solely of
a blind URL.

--~--~-~--~~~---~--~~
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 with threading and sql lib

2009-09-19 Thread John Harrop
On Sat, Sep 19, 2009 at 1:07 AM, Roger Gilliar ro...@gilliar.de wrote:


 Hi,

  re you opening something, using it to return a lazy sequence, and
  then closing it before consuming the sequence?


 No. I started with just opening the database connection in the handler
 function.


You mention threading in the subject and you have a (binding [...] ...)
form. Are you starting a thread, or communicating with one, or using pmap,
future, an agent, or etc. inside the binding, and expecting the binding to
affect the code that runs in the thread/map/future/agent?

--~--~-~--~~~---~--~~
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 with threading and sql lib

2009-09-19 Thread John Harrop
Nothing leaps out at me as a likely cause of a dropped message.
OTOH, the loop/recur at the end is probably better changed to a doseq.

--~--~-~--~~~---~--~~
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: Anyone care to defend/comment some points in this presentation

2009-09-18 Thread John Harrop
On Fri, Sep 18, 2009 at 8:34 AM, Mark Volkmann r.mark.volkm...@gmail.comwrote:

 On Thu, Sep 17, 2009 at 5:22 PM, John Harrop jharrop...@gmail.com wrote:
  On Thu, Sep 17, 2009 at 3:06 PM, Mark Volkmann 
 r.mark.volkm...@gmail.com
  wrote:
 
  On Thu, Sep 17, 2009 at 1:43 PM, z5h bolusm...@gmail.com wrote:
  
   Specifically some problems encountered in Clojure's STM and bytecode
   generation.
  
  
  
 http://www.azulsystems.com/events/javaone_2009/session/2009_J1_JVMLang.pdf
   (Slide's 8 and 20-21)
 
  Slide 20 - Should say Nothing mutable by default and One kind of
  mutable, Refs, guarded by STM
 
  There are three more kinds of mutable: atoms, agents, and mutable Java
  objects. Of those, the latter are to be avoided where possible though,
 and
  only agents are also guarded by STM in any manner.

 Agents are not guarded by STM. It is Refs that can only be modified in
 a transaction. There is a connection between Agents and STM though. If
 you send an action to an Agent within a transaction, it won't actually
 be sent until changes to Refs in the transaction have been committed.


That is what I meant by in any manner; that there's some interaction with
STM. In the case of agents there's no guarding outside of a transaction
context, whereas refs cannot be modified outside of a transaction so are
guarded all the time in some sense.

--~--~-~--~~~---~--~~
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 with threading and sql lib

2009-09-18 Thread John Harrop
On Fri, Sep 18, 2009 at 1:32 PM, rogergl ro...@gilliar.de wrote:

 The problem is that the above code only works if I establish a
 connection outside the handle-client function. Otherwise the first
 reply to my client gets lost.

 Has anyone an explanation for this ?


Are you opening something, using it to return a lazy sequence, and then
closing it before consuming the sequence?

--~--~-~--~~~---~--~~
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: OutOfMemoryError with loop/recur

2009-09-18 Thread John Harrop
On Fri, Sep 18, 2009 at 4:39 PM, Tassilo Horn tass...@member.fsf.orgwrote:

 Although that doesn't really help, the normal `reduce' doesn't do
 better.

 (reduce + (take 100 (iterate inc 1)))  ; works
 (reduce + (take 1000 (iterate inc 1))) ; OutOfMemoryError


Are you sure? I'd expect that with

(def integers (iterate inc 1))

(reduce + (take 1000 integers))

but not with what you wrote. If it does happen with exactly what you wrote
then clojure.core/reduce is holding onto the head, or you had a funny
substitute reduce in whatever namespace you evaluated those in.

--~--~-~--~~~---~--~~
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: Silly Convention Question

2009-09-18 Thread John Harrop
On Fri, Sep 18, 2009 at 4:45 PM, CuppoJava patrickli_2...@hotmail.comwrote:

 Hi,
 After I shot myself in the foot again this morning by naming one of my
 variables cond and then wondering why Clojure was complaining about
 a simple cond form, I thought why don't we have capitalization
 conventions that differ between variables and functions?

 Everything in Clojure is lowercase. Are people too opposed to variable
 names beginning with an upper case character?

 In Java, names that begin with upper case characters denote classes,
 but class names are much less often to be seen in Clojure.

 Thoughts?


A decent IDE will alert you with syntax highlighting (NetBeans w/ enclojure
does, in particular).

It is a bit of a bother that many commonly desirable short-and-meaningful
variable names would shadow clojure.core names or special forms: fn, map,
seq, vec, key, value, and plenty more. I find myself often using names like
f, m, s, k, and v, or similarly.

Sometimes a more meaningful name still is possible, generally in higher
level code; accounts-map for instance. In lower level code though, you may
have say a function that does some kind of reduction over a map with a
particular key. This function is agnostic to whatever higher purpose the map
may serve; it's called by, rather than part of, the business logic. So what
do you call its parameters? I wind up with f, m, and k; it's that or
something like the-fn, the-map, and the-key and that seems verbose.

This arises with any function that performs a generic transformation of data
agnostic as to that data's business-logic purpose.

--~--~-~--~~~---~--~~
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: OutOfMemoryError with loop/recur

2009-09-18 Thread John Harrop
On Fri, Sep 18, 2009 at 3:52 PM, Patrik Fredriksson patri...@gmail.comwrote:


 Hi!

 Could someone please help me understand why the following causes a
 java.lang.OutOfMemoryError: Java heap space for large n:s (10
 works fine, 100 does not).

 (def integers (iterate inc 1))

 (defn limited-reduce [fn coll n]
  (loop [c coll i n result 0]
  (if (zero? i)
result
  (recur
(rest c)
(dec i)
(fn result (first c))

 (limited-reduce + integers 10)

 Many thanks!


With (def integers (iterate inc 1)) you're holding on to the head of the
sequence. Try it with

(defn integers [] (iterate inc 1))

and

(limited-reduce + (integers) 100)

and the OOME should not occur.

--~--~-~--~~~---~--~~
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: Ensure and STM: find the bug...

2009-09-17 Thread John Harrop
On Thu, Sep 17, 2009 at 11:04 AM, Mark Volkmann
r.mark.volkm...@gmail.comwrote:

 On Thu, Sep 17, 2009 at 9:57 AM, Chouser chou...@gmail.com wrote:
 
  On Thu, Sep 17, 2009 at 12:28 AM, Krukow karl.kru...@gmail.com wrote:
 
  Final question. The docs say that 'ensure' permits more concurrency
  than promoting the ref to a write. Is there a quick/simple way of
  explaining how? (Or do I need to go to the source :-)
 
  If you have multiple transactions ensuring the same var but
  no transactions changing it, all those transactions can
  proceed simultaneously.  If they all did dummy writes
  instead of ensure, they could only proceed in order.

 Ah ... I think I misunderstood an important part of the question. I
 wasn't assuming that all the concurrent transactions were going to use
 ensure or a dummy write on the same Ref. So the key is that multiple
 transactions can successfully ensure the same Ref, but multiple
 transactions cannot successfully write the same Ref.


Not with ref-set! or alter!, but maybe with commute identity?

--~--~-~--~~~---~--~~
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: Ensure and STM: find the bug...

2009-09-17 Thread John Harrop
Don't commutes commute with one another, but not with other writes?

--~--~-~--~~~---~--~~
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: Redefining Special Forms

2009-09-17 Thread John Harrop
On Thu, Sep 17, 2009 at 2:49 PM, Stuart Sierra
the.stuart.sie...@gmail.comwrote:


 On Sep 17, 12:40 pm, Gorsal s...@tewebs.com wrote:
  Oh. And just as a quick other question, do global bindings affect
  threads which are started in the same ns?

 I think threads inherit the bindings in effect when they are created.


http://clojure.org/vars strongly implies otherwise; that they see the root
bindings except while a (binding [foo bar] (baz)) form is executing in the
same thread.

Having heritable bindings could be useful, though. Yet wouldn't work for
cases like pmap. Best might be to just use atoms when you want
non-thread-local dynamic bindings: (untested)

(def multiplier (atom 3))

(defn magnify [x]
  (* multiplier x))

(defmacro with-atom-value [[at v]  body]
  `(let [a# ~at
 x# (deref a#)]
 (reset! a# ~v)
 (try
   ~...@body
   (finally
 (reset! a# x#)

...

(with-atom-value [multiplier 4]
  (pmap magnify some-seq))

--~--~-~--~~~---~--~~
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: Redefining Special Forms

2009-09-17 Thread John Harrop
On Thu, Sep 17, 2009 at 6:15 PM, Gorsal s...@tewebs.com wrote:

 Or maybe i could simply push to the global var and in addition to the
 value use a unique gensymed id. Then once the local binding was done
 it would pop until it sees its gensymed id. That would work in the
 situation that a local binding failed to pop its own binding. That
 might work...


Why not just use an atom, if you want it globally, or a single global var
and binding, if you want thread-local values. If you want it changed
globally but put back after, save the value and use try ... finally to
ensure it gets put back.

--~--~-~--~~~---~--~~
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: minor grievance with arithmetic on characters

2009-09-09 Thread John Harrop
On Tue, Sep 8, 2009 at 8:18 PM, Timothy Pratley timothyprat...@gmail.comwrote:


 Hi Steve,

 I find the -1, 0, 1 result more useful, but am also wary it hides some
 useful information. My preference would be to have the doc-string
 changed to what you proposed and keep the neg/pos behaviour
 of .compareTo in place. To get -1, 0, 1 requires a 'sign' operator
 which is handy to have as a separate function - might be a candidate
 for contrib?

 (defn sign
  Returns 1 if x is positive, -1 if x is negative, else 0
  [x]
  (cond (pos? x) 1, (neg? x) -1, :else 0))


(defn sign
 Returns 1 if x is positive, -1 if x is negative, else 0
 [x]
 (compare x 0))

If that doesn't work, then compare on numbers is likely to fail for
widely-separated numbers due to integer underflow or overflow if the Java
compareTo being called does so; compareTo is defined in interface Comparable
as returning a Java int, which has 32 bit range; there's a reason it's
recommended to implement compareTo using  or , ==, ?:, and the literal
values -1, 0, and 1. The char comparison using subtraction is safe since all
differences between 16-bit numbers fit in an int, but this is not true for
int, long, or bignum comparison by subtracting and then narrowing to int.

For the native Java Integer, Long, and BigInteger types this is highly
unlikely to be the case. I'm hoping Clojure's Ratio class's compareTo is
also safe.

This is assuming the Clojure compare function on numbers works by coercing
them along the graph
Byte-(Short,Character)-Int-Long-BigInteger-Ratio-BigDecimal,
Float-Double-BigDecimal and then using compareTo, as seems likely.

(I don't currently have my REPL or the source code handy to check.)

--~--~-~--~~~---~--~~
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: dynamic :use

2009-09-07 Thread John Harrop
Or, you can go the opposite way and write a macro that expands into the
appropriate ns form. This will work if the information you need from
*db-adapter* is there by macroexpansion time.

A macro that does a similar job to ns, but adds conditional features to the
ns DSL, can wrap and generalize what Chouser suggests and will work if
*db-adapter*'s information isn't available until runtime. The macro would
allow something like what you originally tried to do, with your-ns replacing
ns, and expand in that case into code like Chouser suggested.

--~--~-~--~~~---~--~~
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: best way to make use of association lists

2009-09-07 Thread John Harrop
On Mon, Sep 7, 2009 at 5:19 PM, Conrad drc...@gmail.com wrote:

 Alternatively, I suppose it would be possible to create a new type of
 map that performs better than an alist but can return items in the
 order they were added to the list, if desired


Or use an existing type: the java.util.LinkedHashMap. The downside is, it's
a mutable Java Map and not a Clojure map.

--~--~-~--~~~---~--~~
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: Tight loop performance

2009-09-06 Thread John Harrop
Besides using just aset, try using unchecked-inc instead of inc.

--~--~-~--~~~---~--~~
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: Tight loop performance

2009-09-06 Thread John Harrop
Try unchecked-inc and try wrapping the function body in (let [words (int
words)] ... ).
I don't know why aset is still reflecting when all of the arguments are
type-hinted, but the above changes might speed up some other bits of the
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: Filter Causing StackOverflowError?

2009-09-02 Thread John Harrop
On Wed, Sep 2, 2009 at 1:02 PM, tmountain tinymount...@gmail.com wrote:


 Hi all - I've recently encouraged a friend to start learning Clojure,
 and he has written some basic Markov chaining code as a learning
 exercise. His code works fine with small sets of input data, but
 larger inputs have been causing a StackOverflowError.

 I've taken a look at the code and suspect that the error may be caused
 by recurrent calls to filter occupying increasing amounts of stack
 space due to filter leaving closed-over locals hanging around. That
 being said, this is only a suspicion, I'm still learning the language
 myself, so I could be totally wrong. Wrapping the filter calls in
 doall seems to prevent the problem from happening, but performance is
 abysmal in that case.


The problem is laziness: you have a loop/recur that layers on successive
filters. Then when you go to realize an element, it calls filter, which
calls filter, which calls filter ... however deep. Unfortunately, if you
apply successive lazy operations to a seq in a loop/recur you sort of lose
tail optimization because of this, and there doesn't seem to be a way to
make lazy operations that call other lazy operations tail-optimized. At
least, not yet.

At least for now you will probably have to doall the seq every so many
iterations to avoid the stack overflow. If doing it every iteration kills
performance, you might try doing it every Nth for some value of N that's
reasonably large, but small enough to avoid the overflow.

--~--~-~--~~~---~--~~
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: Two possible additions: non-reflective classobject calls support for map-conj on arrays

2009-09-01 Thread John Harrop
On Tue, Sep 1, 2009 at 10:40 AM, Rich Hickey richhic...@gmail.com wrote:

 On Mon, Aug 31, 2009 at 10:55 AM, Krukowkarl.kru...@gmail.com wrote:
 
  I have two minor minor suggestions for Clojure changes.
 
  1) Consider this function:
  user (set! *warn-on-reflection* true)
  true
  user (defn reader-from-classpath [s]
   (- (.getResourceAsStream java.lang.String s)
   (java.io.InputStreamReader.)
   (java.io.BufferedReader.)))
  Reflection warning, NO_SOURCE_PATH:2 - call to getResourceAsStream
  can't be resolved.
  #'user/reader-from-classpath
 
  In general, I think every call of form (.instanceMember Classname
  args*) will generate such a warning since it expands to, e.g.,
 
  user (macroexpand ' (.getResourceAsStream java.lang.String s))
  (. (clojure.core/identity java.lang.String) getResourceAsStream s)
  user



#1 is fine idea. I've implemented the hinting in the compiler where
 that expansion takes place. (commit  e45046da8f)


Why is there a call to identity at all? Why not just (. java.lang.String
getResourceAsStream s)?

--~--~-~--~~~---~--~~
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: vs. Python

2009-08-31 Thread John Harrop
On Mon, Aug 31, 2009 at 5:15 PM, Brian Hurt bhur...@gmail.com wrote:

 If I recall correctly (and correct me if I'm wrong), Python uses a
 reference counting garbage collector.  Which means as soon as the reference
 to the object goes away, the object gets collected and the handle closed.
 Most JVMs use some form of mark  sweep algorithm, which means it may be
 some time before the object gets collected (and the resource freed).  This
 is especially the case in a generational GC system, where long-lived objects
 get collected much less frequently.  So, for long-running programs, it's
 possible to pile up uncollected resources to the point where you run out of
 the resource, simply because unused objects haven't been collected yet.


This suggests that when low-level JVM functions that try to get a file
handle, socket, or what-not from the OS fail they should invoke the garbage
collector in a full stop-the-world collection and then retry, just as the
memory allocator already does, and throw the IOException only if they still
fail afterward. (These resources tend to have finalizers, so the GC should
be run twice back-to-back to collect them, or even repeatedly until no
garbage was collected.)

Then most cases of this would cause the occasional very slow file handle
acquisition instead of a crash or other error.

Generally, when you open a file descriptor, you should always make sure it's
 gets closed when you're done with it.


But I do agree with this. Finalizers and gc of objects holding native
resources are a safety net; it's better not to fall into it even when it's
there. You might not die but the judges will be holding up placards reading
0.0, 0.1, 0.0, 1.2, 0.3 or some such after your performance. :)

--~--~-~--~~~---~--~~
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: vs. Python

2009-08-31 Thread John Harrop
On Mon, Aug 31, 2009 at 5:04 PM, Brian Hurt bhur...@gmail.com wrote:

 On Sun, Aug 30, 2009 at 9:31 AM, Jason Baker amnorv...@gmail.com wrote:

 On Aug 30, 2:24 am, Dan Fichter daniel.fich...@gmail.com wrote:
  The Clojure version is more concise and radically safer but a little
 more
  conceptually packed.  Is it worth your trouble?

 Being primarily a Python programmer, I can say that the first thing my
 co-workers would say is that Clojure isn't as readable as Python is.



 Any language you are familiar and comfortable with is going to seem much
 more readable and much more intuitive than a language you are unfamiliar
 with.  Even similarity to English presupposes a familiarity with and comfort
 with English- something most people on this planet don't have.  A native
 English speaker would find a programming language whose syntax was based on,
 say, Mandarin or Swahili, very unintuitive.

 The point here is that arguing in favor of a new language on the basis of
 intuitiveness and readability is a losing argument.


That may depend on the audience. If the audience is a bunch of Python
programmers, similarities to Python may be quite relevant and not comprise a
losing argument.

--~--~-~--~~~---~--~~
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: A complete documentation (downloadable)

2009-08-31 Thread John Harrop
On Mon, Aug 31, 2009 at 3:45 PM, freddi301 gobi...@gmail.com wrote:


 are there a complete clojure documentation ?


There's the documentation at clojure.org; you could spider it with wget,
though with some sites you need to spoof the user-agent and/or hack wget to
disable retrieving robots.txt to do that. (Ethical, IMO, if your intent is
to save hammering that server for bandwidth in the future by having a local
copy.)

There's also the (doc foo) form at the repl. All the API documentation is
there. Unfortunately, *only* the API documentation is there; it would be
nice if, at the very least, (doc a-special-form-name) provided a brief
synopsis instead of just the web site's URL, for the convenience of having
more of it in one place and zero task-switches away from your open project
windows, and also more information findable via find-doc.

--~--~-~--~~~---~--~~
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/EPL and the GPL

2009-08-30 Thread John Harrop
On Sun, Aug 30, 2009 at 7:57 AM, Jan Rychter j...@rychter.com wrote:


 Tassilo Horn tass...@member.fsf.org writes:
 [...]
  BTW: What's the reason that Clojure is licensed under the EPL and the
  contrib stuff under CPL?  Since clojure is not really eclipse-related, I
  don't see a good rationale.  IMHO, the Lesser GPL would be a much better
  fit.  Then you can use clojure also in commercial apps (I guess that was
  the rationale behind EPL), but still you can use it in projects with any
  other free-software license, may it be EPL, GPL or whatever...

 The GPL and LGPL are very restrictive licenses. While most people only
 focus on the source code availability issue, the real show-stopper for
 most commercial usage is the anti-patent clause that exists in both the
 GPL and LGPL. This clause is a potential landmine, even though little
 attention is paid to it. It exists in the same form in both the GPL and
 LGPL.


Version 3 only, and according to
http://news.cnet.com/FSF-rebuts-anti-GPL-3-claims/2100-7344_3-6119987.html

The Linux programmers also expressed concern that a new patent provision in
the draft GPL 3 poses risks to corporations' patent portfolios--a concern
shared by Hewlett-Packard. The foundation said that interpretation is
incorrect.

The GPL 3 simply says that if someone has a patent covering XYZ, and
distributes a GPL-covered program to do XYZ, he can't sue the program's
subsequent users, redistributors and improvers for doing XYZ with their own
versions of that program, the foundation said. This has no effect on other
patents which that program does not implement.

Which means it only affects software patents (which have just been rendered
invalid by in re Bilski anyway) and only to the extent of indemnifying users
and distributors of a GPL-covered program from infringement claims arising
from the use and distribution of that code. If they, say, infringed an HP
patent on print head design making a laser printer they'd not be covered; HP
could still sue.

It no more affects a company's important patents than any version affects a
company's important copyrights. It just stops them extending same to the
GPL'd code and making it effectively proprietary.

--~--~-~--~~~---~--~~
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 am I getting this performance result from Clojure CLR's LispReader?

2009-08-30 Thread John Harrop
On Sun, Aug 30, 2009 at 10:40 AM, Jason Baker amnorv...@gmail.com wrote:


 I've written a test that does this:

public void ReadFile(TextReader infile)
{
using (var text_reader = new PushbackTextReader(infile)) {
LispReader.read(text_reader, false, null, true);
}
}

 ...in a loop.  I'm running this operation a specified number of times
 and then getting an average runtime.  The thing is, if I run this more
 times, the average time goes down.  Is something getting cached and/or
 memoized somewhere, or is this just a bad way to test performance?

 (And FYI, the TextReader that's getting passed in is a StringReader so
 I can eliminate I/O time from the results)


Given that last, I/O buffering and OS disk caching seem doubtful. JIT
perhaps.

--~--~-~--~~~---~--~~
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: assoc-in-by

2009-08-30 Thread John Harrop
On Sun, Aug 30, 2009 at 4:14 PM, kyle smith the1physic...@gmail.com wrote:


 I wrote this based on assoc-in.  If anyone thinks this should be in
 core or contrib, feel free to use it.

 (defn assoc-in-by
  'Updates' a value in a nested associative structure, where ks is a
  sequence of keys and (f v) is the new value and returns a new nested
 structure.
  If any levels do not exist, hash-maps will be created.
  [m [k  ks] f]
  (if ks
(assoc m k (assoc-in-by (get m k) ks f))
(assoc m k (f (get m k)


Nifty and seems to work. Here's a little demo:
user= (assoc-in-by nil [:a :b :c] #(if (nil? %) 1 (inc %)))
{:a {:b {:c 1}}}
user= (assoc-in-by *1 [:a :b :c] #(if (nil? %) 1 (inc %)))
{:a {:b {:c 2}}}
user= (assoc-in-by *1 [:a :b :c] #(if (nil? %) 1 (inc %)))
{:a {:b {:c 3}}}
user= (assoc-in-by *1 [:a :b :c] #(if (nil? %) 1 (inc %)))
{:a {:b {:c 4}}}
which has a counter incrementing.

And it's swap! and alter!-compatible:

(swap! foo assoc-in-by [:a :b :c] #(bar % baz))

Maybe a version that takes more args?

(defn assoc-in-by
 'Updates' a value in a nested associative structure, where ks is a
 sequence of keys and (f v) is the new value and returns a new nested
structure.
 If any levels do not exist, hash-maps will be created.
 ([m [k  ks] f]
   (if ks
 (assoc m k (assoc-in-by (get m k) ks f))
 (assoc m k (f (get m k)
 ([m [k  ks] f args]
   (if ks
 (assoc m k (assoc-in-by (get m k) ks f args))
 (assoc m k (apply f (get m k) args)

which simplifies the swap! example to:

(swap! foo assoc-in-by [:a :b :c] bar baz)

--~--~-~--~~~---~--~~
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/EPL and the GPL

2009-08-29 Thread John Harrop
This is a problem.
The GPL is a very popular open source license. If a language does not permit
developers to use the GPL, that language may be severely reducing the number
of developers willing to adopt it.

It would be desirable for clojure.lang and clojure.core to use a modified
license, something perhaps describable as EPL with classpath exception,
that expressly allows linking with GPL code (with classpath exception or
similar to avoid violating the GPL instead).

Alternatively, dual-licensing lang and core under both the GPL and the EPL
would be possible. Thanks to the contributor agreements, it wouldn't be
necessary to track down all the contributors and get their individual
permission for this, unless the agreements had reciprocal clauses limiting
how Rich could relicense the code base. (I haven't seen them, so wouldn't
know.)

Regardless, this problem bears thinking about and perhaps eventually doing
something about.

--~--~-~--~~~---~--~~
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/EPL and the GPL

2009-08-29 Thread John Harrop
On Sat, Aug 29, 2009 at 12:00 PM, Rich Hickey richhic...@gmail.com wrote:


 This has been discussed as nauseam before:


 http://groups.google.com/group/clojure/browse_frm/thread/6e99caafcf2bbedf/b5519cc219a5baeb

 Nothing has changed, so let's give it a rest, please.


This may be a tempest in a tea-pot, at least where GPLv3 is concerned:

http://www.gnu.org/licenses/quick-guide-gplv3.html

Both versions of the GPL require you to provide all the source necessary to
build the software, including supporting libraries, compilation scripts, and
so on. They also draw the line at System Libraries: you're not required to
provide the source for certain core components of the operating system, such
as the C library.

GPLv3 has adjusted the definition of System Library to include software that
may not come directly with the operating system, but that all users of the
software can reasonably be expected to have. For example, it now also
includes the standard libraries of common programming languages such as
Python and Ruby.

If the software is written in Clojure, then clojure.jar is something that
all users of the software can reasonably be expected to have, is it not?
That means clojure.jar can be combined with GPLv3 code, if I'm not mistaken,
since doing so apparently doesn't violate the GPLv3 or the EPL.

It even apparently allows combining with GPLv2 or any later version in
that anyone redistributing it can (but must) use GPLv3 or later. :)

--~--~-~--~~~---~--~~
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: Java STM

2009-08-28 Thread John Harrop
On Fri, Aug 28, 2009 at 4:45 AM, peter veentjer alarmnum...@gmail.comwrote:

  Clojure's STM is part of a holistic language design where
  people will normally be programming with immutable persistent
  composite data structures. Getting a consistent view of such a data
  structure doesn't require a transaction at all, so that is much faster
  than other strategies. When 'changing' a data structure, you read it
  from the ref once and then structural changes do not involve the STM
  or refs. Store it back in the ref when done. Thus the granularity of
  transactions is coarse and the number of ref interactions involved
  small. These are not things you'll see when timing pounding an integer
  in a transactional ref in a tight loop, but matter greatly in
  practice, IMO.

 I partly agree. One of my design guidelines is that one should not
 have to pay
 for what is not being used.

 One of the things I'm focussing on is making the transaction
 as fast as possible for any length. I'm working on a system that
 advices the
 creation of a transaction with the maximum number of attached objects.
 I have
  a transaction optimised for a single attachment (5+M transactions/
 second on a single core),
 for a small number of attachments (so using an array to store attached
 items to reduce object creation)
 and one for a large number of attachments (so using an expensive
 hashmap).
 The later one also is going to get a parallel commit (so obtaining
 locks/checking for
 isolation problems.. and doing the write) to make effective use of the
 cores and speed
 up the commit of larger transactions.


For a single attachment Clojure has atoms and agents instead of an
optimized specialization of refs and dosync. :)

--~--~-~--~~~---~--~~
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: Lazy Exceptions

2009-08-28 Thread John Harrop
On Fri, Aug 28, 2009 at 8:50 AM, Rich Hickey richhic...@gmail.com wrote:


 On Thu, Aug 27, 2009 at 8:10 PM, Tim Snydertsnyder...@gmail.com wrote:
 
  Well, I can see that LazySeq does indeed catch and wrap all Exceptions
  in a RuntimeException.  I also think I can work around it, but I'd
  like to know why this was done?
 
  Was it necessary given the checked vs. unchecked exception system of
  Java?
 

 Yes.


What about declaring IFn.invoke() as throws Exception? Or did you think
that would make calling Clojure from Java too painful? Or was there some
other reason?

--~--~-~--~~~---~--~~
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: Order of keys within a map?

2009-08-27 Thread John Harrop
On Thu, Aug 27, 2009 at 3:35 PM, Howard Lewis Ship hls...@gmail.com wrote:


 Is the order of keys in a map predictable?  I have some tests I'm
 concerned about, where the keys and values in a map are converted to a
 string (ultimately, a URL, as query parameters) and the order will
 affect the output string.

 I could sort the keys, but then I'm changing my code to support the
 test in a somewhat non-trivial way.

 Literally: when iterating over the key/value pairs, the order seems to
 be the order in which the key/values are defined in the map. Is this
 true?


The order of keys in a map is basically undefined. In practice, for small
maps it tends to be insertion order and for maps with more than eight keys,
in order of the keys' hashCode() values (as Java objects). But this behavior
should probably not be relied on.

--~--~-~--~~~---~--~~
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: we offer cheap sport shoes men's shoe(www.salegood8.com) casual shoe fashion shoe

2009-08-26 Thread John Harrop
On Tue, Aug 25, 2009 at 11:42 AM, Chouser chou...@gmail.com wrote:


 On Tue, Aug 25, 2009 at 10:36 AM, John Harropjharrop...@gmail.com wrote:
  What the hell?

 The group actually gets a steady stream of spam, but it
 usually gets deleted instead of being sent to everyone.  On
 this one I accidentally clicked the wrong button.  Sorry
 about that.


I'd have thought you'd have set up an automatic filter for the shoe spammer.
The messages should after all be very easy to identify with automation.
There are plenty of people on an auto-accept list; this one, at least, seems
to cry out for an auto-reject list. :)

--~--~-~--~~~---~--~~
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: On the reader macro #=

2009-08-26 Thread John Harrop
On Wed, Aug 26, 2009 at 1:13 PM, John Harrop jharrop...@gmail.com wrote:

 This is important to know about for security reasons, also. Specifically,
 if you are receiving Clojure data structures in text form over the network,
 and don't set *read-eval* to false, you're vulnerable to a Clojure
 injection attack. Someone could send you (+ 5 #=(System/exit 0)) as a
 denial-of-service attack, just for starters.


Interesting result from testing this:

user= (read-string (System/exit 0))
(System/exit 0)
user= (read-string #=(System/exit 0))
ClassNotFoundException: System
user= (read-string #=(java.lang.System/exit 0))

REPL is disconnected.

Strange that java.lang is not apparently imported in whatever environment
the EvalReader uses. Doesn't stop it being a security hole if accessible
over the network though. :)

--~--~-~--~~~---~--~~
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: On the reader macro #=

2009-08-26 Thread John Harrop
This is important to know about for security reasons, also. Specifically, if
you are receiving Clojure data structures in text form over the network, and
don't set *read-eval* to false, you're vulnerable to a Clojure injection
attack. Someone could send you (+ 5 #=(System/exit 0)) as a
denial-of-service attack, just for starters.
I doubt there's a way to make it safe. There's probably no way to force
those expressions to run in an applet sanbox, at least without massive
kludging. You'd have to vet the strings first, using some non-Clojure-reader
parser. Easier to use the Clojure reader and then walk the resulting data
structures looking for, say, special sentinel keywords that should be
substituted with other things, or that flag something about the following
item (say, that it should be converted to a SortedMap).

For storing stuff locally the EvalReader should be safe, unless your
program runs with elevated privileges compared to the user who runs it (unix
setuid or equivalent). In that event though there's a possibility of it
being exploited for local privilege escalation. Arbitrary Clojure and Java
code could be submitted to be run at the higher privilege level.

--~--~-~--~~~---~--~~
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: we offer cheap sport shoes men's shoe(www.salegood8.com) casual shoe fashion shoe

2009-08-25 Thread John Harrop
What the hell?

--~--~-~--~~~---~--~~
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: Generation of random sequences

2009-08-25 Thread John Harrop
On Tue, Aug 25, 2009 at 10:42 AM, Fogus mefo...@gmail.com wrote:


 A quick and dirty way would be to use a map as your intermediate
 storage with your generated numbers as keys and some constant as their
 assoc'd value.  Once you've populated said map with the proper number
 of entries (keeping track of clashes along the way) then get a
 sequence using `(seq (.keySet myMap))`.


Why not just use a HashSet rather than a SortedSet to begin with?

--~--~-~--~~~---~--~~
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: Arity count

2009-08-19 Thread John Harrop
On Wed, Aug 19, 2009 at 10:03 AM, Achim Passen achim.pas...@gmail.comwrote:

 Beware! This snippet relies on unexposed details of clojure's current
 implementation. It might stop working tomorrow, so it's definitely not
 intended for production use, but it might help with debbuging/exploring.


Meanwhile, for declared functions this works:

(map #(if (contains? (set %) ') [:more (- (count %) 2)] (count %))
(:arglists ^#'foo))

giving results like:

(0 2 5 [:more 7])

(in this case for (defn foo ([] nil) ([glorb fuzzle] nil) ([x y z w u] x)
([a b c d e f g  more] more)))

Add this:

(defn accepts-arity [arities arity]
  (or
(contains? (set arities) arity)
(and (vector? (last arities)) (= arity (second (last arities))

and you can check if the function accepts a particular arity. (This expects
arities in the format output by my map expression. In particular, a list
of numerical arities and possibly a [:more n] entry, which must be a vector
and must be the last item in the list if present, and n must be the number
of required parameters for the  more overload.)

Wrap it all up with two macros:

(defmacro fn-arities [fn-name]
  `(map (fn [x#] (if (contains? (set x#) ') [:more (- (count x#) 2)] (count
x#))) (:arglists ^#'~fn-name)))

(defmacro fn-accepts-arity [fn-name arity]
  `(accepts-arity (fn-arities ~fn-name) ~arity))

user= (fn-accepts-arity foo 8)
true
user= (fn-accepts-arity foo 6)
false
user= (fn-accepts-arity reduce 2)
true
user= (fn-accepts-arity reduce 3)
true
user= (fn-accepts-arity reduce 4)
false
user= (fn-arities map)
(2 3 4 [:more 4])

Works for macros, too:

user= (fn-arities fn-arities)
(1)
user= (fn-arities fn-accepts-arity)
(2)

But, as noted, only works with a name of a declared fn or macro:

user= (fn-arities #(+ 3 %))
#CompilerException java.lang.ClassCastException: clojure.lang.Cons cannot
be cast to clojure.lang.Symbol (NO_SOURCE_FILE:110)

(One thing odd about that:

user= (class '#(+ 3 %))
clojure.lang.PersistentList

not Cons. Hmm.)

It also doesn't work with local, named functions, either using let or using
letfn, even if (fn name [args] body) is used and not (fn [args] body):

user= (let [x (fn [a] (+ 3 a))] (fn-arities x))
#CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:117)
user= (let [x (fn x [a] (+ 3 a))] (fn-arities x))
#CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:118)
user= (letfn [(x [a] (+ 3 a))] (fn-arities x))
#CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:119)

--~--~-~--~~~---~--~~
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: Can dosync transaction result computation be parallelized over multiple threads?

2009-08-19 Thread John Harrop
(def *dosync-counts* (atom {})
(defn avg-in [map key val]
  (let [[avg cnt] (get map key [0 0])]
(assoc map key [(/ (+ (* avg cnt) val) (inc cnt)) (inc cnt)])))

(defmacro logged-dosync [ body]
  `(let [count# (atom 0)]
 (dosync
   (swap! count# inc)
   ~...@body)
 (swap! *dosync-counts* avg-in (quote ~body) (deref count#

(defn crude-print-dosync-log []
  (doseq [[code [avg cnt]] @*dosync-counts*]
(println code)
(println avg retries on average over cnt total transaction(s))
(println)))

These tools should suffice to simply discover how many retries some
transaction is taking on average. For more complex dosync profiling you'd
probably need hooks deeper into Clojure's STM, particularly for logging what
ref value changed to cause a retry or similarly.

(A cleverer macro might parse the body for ensures, commutes, and the like,
and bookend the body with code to record the at-start-of-transaction values
of the involved refs and code to compare these against the out-transaction
values just before commit, getting the latter using (future (deref foo)) or
some similar method that will see the out-transaction values, and note any
that had changed. So hooks deeper into STM might not be necessary after all,
at least for some simple tests of why a retry might have happened. Having
code that can introspect on code and write code seems to allow for some
serious kung-fu!)

--~--~-~--~~~---~--~~
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: New string utilities library ready

2009-08-19 Thread John Harrop
On Thu, Aug 20, 2009 at 12:45 AM, samppi rbysam...@gmail.com wrote:


 For me, I'd like it if the core functions had the data as the first
 argument, but have a special function—I can't come up with a better
 name than partial-2—so that (partial-2 function opt1 opt2 opt3) is
 equivalent to (fn [data] (function data opt1 opt2 opt3)). That way, I
 could do things like (map (partial-2 s/split #\n 30) vector-of-strs)
 without breaking .


Is there something wrong with (map #(s/split % #\n 30) vector-of-strs)?

The #(...) lambda read-macro seems to me to obviate most needs for partial
and partial-2.

--~--~-~--~~~---~--~~
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: Idiom for array slicing

2009-08-18 Thread John Harrop
On Mon, Aug 17, 2009 at 11:35 PM, Mark Triggs mark.h.tri...@gmail.comwrote:


 Thanks all.  So combining a few suggested ideas:

  (defn slice
  Return the items in coll at index positions keys.

   (slice [0 4 6] \abcdefg\) = (\\a \\e \\g)
[keys coll]
(let [max-idx (apply max keys)
  keyset (set keys)]
  (map second
   (filter (fn [[idx _]] (keyset idx))
   (take-while (fn [[idx _]] (= idx max-idx))
   (indexed coll))

 This version has the advantage of working on infinite sequences and not
 hanging onto the head.  This works as expected:

  (slice [200 201] (repeatedly #(int-array 102400)))

 without blowing up the stack or throwing OutOfMemory (on my JVM).


So does the very simple

(defn slice [indices coll]
  (map #(nth coll %) indices))

though that doesn't use keys rather than position with maps.

(defn slice [indices coll]
  (map #(get coll %) indices))

does, but works for maps and vectors but not lists. It does work for
strings.

(defn slice [indices coll]
  (map #(get (indexed coll) %) indices))

should if (indexed coll) has the semantics it seems it should from what
you've posted, but the indexed function is apparently bleeding-edge because
my copy of clojure 1.0 doesn't have anything by that name in it.

(defn slice [coll  indices]
  (map #(nth coll %) indices))

has the same argument syntax as suggested originally by Mark.

--~--~-~--~~~---~--~~
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: what's the appropriate way to process inner nested list (or vector) in clojure?

2009-08-16 Thread John Harrop
On Sun, Aug 16, 2009 at 1:30 AM, botgerry botge...@gmail.com wrote:


 Hello,all

 new to functional programming, I have one nested dynamic vecter just
 like this:

 (def a [[1 2 3 4] [ok 89 22] [25 78 99] ...]]

 it has to support ops:
 1*   add new item,it's easy: eg. (conj   a  [metoo oops] )
 2*  insert one element  into inner vector based that vector's
 content,eg  i have to append 50 in inner vectors which includes 99.
 the result  is [[1 2 3 4] [ok 89 22] [25 78 99 50]...]
 3*  merge inner vectors in a , eg. if there are same elements in
 inner vectors , they should be merged and delete same elements.
  [[1 2 3 4] [ ok 89 22] [ 5 6 7 2 ]...] - [[1 2 3 4 5 6 7] [ok 89
 22]]


If you are implementing a disjoint set forest, it might be better to use a
map from values to sets, where the lookup-set-given-value operation is a
simple map lookup, adding a new one-element set is just (assoc map object
#{object}), and merging two sets is almost as simple:

(let [new-set (into set-1 set-2)]
  (reduce #(assoc %1 %2 new-set) map new-set))

evaluates to the new forest map.

--~--~-~--~~~---~--~~
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 success story ... hopefully :-)

2009-08-15 Thread John Harrop
On Fri, Aug 14, 2009 at 7:18 PM, bradford cross
bradford.n.cr...@gmail.comwrote:

 Hi Chad, yep, that was me.  We do hope to open source some stuff soon.

 First will probably be our wrappers for cascading/hadoop and s3.

 Next might be some core language extensions which might be good in contrib
 or some other lib.

 If we release any basic stats or machine learning stuff we may try to merge
 into incanter if it seems like a fit but haven't had time to check out
 incanter as I'd like.


Very interesting.

Are you using

(binding [*read-eval* false]
  ...)

when reading Clojure data structures out of strings obtained over your
distributed node network? If you're not it's possible you have a security
hole that could be exploited by a hostile node masquerading as a legitimate
one. (Though likely an attacker would have to penetrate your firewall and
get loose in your LAN, gaining privileges on at least one of your machines,
to exploit it.)

Specifically, a #=() form in the stream would otherwise allow a sort of
injection attack. If you use the Clojure reader on other untrusted data,
such as fragments of web pages (to parse numbers, say), the same applies:
without that binding for those reads, you may be vulnerable in a similar
manner. If data from web forms, vulnerable in a very similar manner to SQL
injection.

Security becomes especially important if you figure to do big parallel
reductions on office PC spare cycles instead of dedicated hardware. Those
PCs might vary in how sensitive the information on them is, and in how
trustworthy their users are. You don't want a newly-hired clerk in sales
sending crafted network packets that give him privileges on the desktop
computer of the CFO or among the RD department's boxes. The latter lets him
sell industrial espionage data to the highest bidder, likely a competitor;
the former, possibly do some insider trading or suchlike (and when the SEC
shows up to investigate some suspicious trades, they'll be looking at your
CFO, as he was the one nominally privy to the inside info). So a breach
could cause anything from embarrassment (porn popups during board meeting
Powerpoint presentations; intentional pranks) to competitive or legal
trouble.

--~--~-~--~~~---~--~~
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: Can Clojure be as fast as Java?

2009-08-12 Thread John Harrop
On Wed, Aug 12, 2009 at 5:25 AM, Piyush Ranjan piyush...@gmail.com wrote:

 This is a troll question. I have seen similar questions posted on other
 forums about languages like ruby, CL, Haskell, Prolog, C, C++, fortran,
 bigloo(?) etc by the same poster.


Hmm. fft1976 = WrexSoul?

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

2009-08-12 Thread John Harrop
On Thu, Aug 13, 2009 at 12:34 AM, Richard Newman holyg...@gmail.com wrote:

 This is the difference between 'conventional' and point-free style, by
 the way. Many people view point-free as being somehow more elegant,
 and I'm generally inclined to agree... apart from in cases like your
 example, where a ton of partials need to be added.


What is point-free, exactly?

--~--~-~--~~~---~--~~
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: core.clj: 'into' definition

2009-08-11 Thread John Harrop
On Tue, Aug 11, 2009 at 6:39 AM, Krukow karl.kru...@gmail.com wrote:


 I was browsing through core when I noticed something I didn't
 understand in 'into' (from core.clj):

 ;redef into with batch support
 (defn into
  Returns a new coll consisting of to-coll with all of the items of
  from-coll conjoined.
  [to from]
  (if (instance? clojure.lang.IEditableCollection to)
(#(loop [ret (transient to) items (seq from)]
(if items
  (recur (conj! ret (first items)) (next items))
  (persistent! ret
(#(loop [ret to items (seq from)]
(if items
  (recur (conj ret (first items)) (next items))
  ret)

 I am wondering about the construct #(loop ...). As far as I can see
 you might as well just use (loop). I.e.,

 (defn into2
  Returns a new coll consisting of to-coll with all of the items of
  from-coll conjoined.
  [to from]
  (if (instance? clojure.lang.IEditableCollection to)
(loop [ret (transient to) items (seq from)]
(if items
  (recur (conj! ret (first items)) (next items))
  (persistent! ret)))
(loop [ret to items (seq from)]
(if items
  (recur (conj ret (first items)) (next items))
  ret

 I suspect that I am missing some point. Could someone clarify?


I don't know. Perhaps at this point during bootstrap loop doesn't create
recur points and so the anonymous lambdas are necessary? But then recur
would rebind the (nonexistent) lambda parameters I'd have thought.

--~--~-~--~~~---~--~~
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: binary serialization

2009-08-11 Thread John Harrop
On Mon, Aug 10, 2009 at 10:57 PM, Kyle R. Burton kyle.bur...@gmail.comwrote:

 On Mon, Aug 10, 2009 at 10:42 PM, Kyle R. Burtonkyle.bur...@gmail.com
 wrote:Sorry, forgot to offer up the inverse of freeze, thaw:

 (defn thaw [bytes]
  (with-open [bais (java.io.ByteArrayInputStream. bytes)
  ois  (java.io.ObjectInputStream. bais)]
(.readObject ois)))


 Regards,

 Kyle


Which in turn gives us this, otherwise sorely lacking from the Java standard
library, but much less useful to us Clojurians who tend to mainly use
immutable objects:

(defn deep-copy [obj]
  (thaw (freeze obj)))

(Object.clone() does a shallow copy and typically isn't as widely available
as Serializable.)

--~--~-~--~~~---~--~~
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: binary serialization

2009-08-11 Thread John Harrop
On Tue, Aug 11, 2009 at 12:17 AM, fft1976 fft1...@gmail.com wrote:

 I don't know JVM too well, but I think no efficient user-level
 solution is possible. Why? To take care of substructure sharing, you
 need to remember a set of shareable values that have already been
 serialized, and do reference equality comparisons when new new
 substructures are serialized.

 This comparison and a set implementation can easily be done with
 pointers (because you have ), but there are no pointers in the JVM,
 and no reference inequality, so you must use linear seeks, making
 the time complexity of serialization quadratic, where in C/C++ it
 could be O(N log N)


Reference equality is available in the JVM (instructions if_acmpeq and
if_acmpne), in Java (operators == and !=), and in Clojure (predicate
identical?). Furthermore, though  on pointers isn't, so a tree-map of
already serialized structures to themselves also isn't, Java provides
System.identityHashCode() and IdentityHashMap. These use a hash that
respects reference equality. So one in fact can implement one's own
serialization that is O(n) using O(1) hashmap lookups (and using reflection,
and not working if SecurityManager won't let you setAccessible private
fields and the like, so not in an unsigned applet).

(Another use for reference equality is to see if Double.valueOf() is
caching, something that arose as an issue in another thread. On my system,
Sun JVM 1.6.0_13 -server and Clojure 1.0.0, it apparently is not:

user= (identical? 2.0 2.0)
false

If this comes out to true then it's caching. Integer.valueOf() is caching on
my system, but only for small integers:

user= (identical? 1 1)
true
user= (identical? 5 5)
true
user= (identical? 50 50)
true
user= (identical? 500 500)
false
user= (identical? 255 255)
false
user= (identical? 127 127)
true
user= (identical? 128 128)
false

The threshold seems to be at values that will fit in one byte.

[Remember the literals get boxed when passed to a function like identical?
that isn't inlined. And identical? isn't inlined:

user= (meta (var identical?))
{:ns #Namespace clojure.core, :name identical?, :doc Tests if 2 arguments
are the same object, :arglists ([x y])}

whereas two-argument + is:

user= (meta (var +))
{:ns #Namespace clojure.core, :name +, :file clojure/core.clj, :line
549, :arglists ([] [x] [x y] [x y  more]), :inline-arities #{2}, :inline
#core$fn__3329 clojure.core$fn__3...@d337d3, :doc Returns the sum of
nums. (+) returns 0.}

You can also use ^#'identical? and ^#'+ but I like my Clojure looking like
Lisp, not like perl. :)])

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-11 Thread John Harrop
On Fri, Aug 7, 2009 at 8:14 PM, John Harrop jharrop...@gmail.com wrote:

 Your core loop seems to be:
 (loop [zr (double 0.0)
  zi (double 0.0)
  zr2 (double 0.0)
  zi2 (double 0.0)
  iterations-remaining iterations-remaining]
 (if (and (not (neg? iterations-remaining))
  ( (+ zr2 zi2) limit-square))
   (let [new-zi (double (+ (* (* f2 zr) zi) pi))
 new-zr (double (+ (- zr2 zi2) pr))
 new-zr2 (double (* new-zr new-zr))
 new-zi2 (double (* new-zi new-zi))]
 (recur new-zr new-zi new-zr2 new-zi2 (dec iterations-remaining)))

 What I suggest is

 (loop [zr (double 0.0)
zi (double 0.0)
i (int (inc iterations-remaining))]
   (let [zr2 (* zr zr)
 zi2 (* zi zi)]
 (if (and (not (= 0 i)) ( (+ zr2 zi2 limit-square)))
(recur (+ (- zr2 zi2) pr) (+ (* (* f2 zr) zi) pi) (unchecked-inc i))
(whatever...

 * Same calculations
 * Less items in recur rebind
 * Counter is also primitive

 (untested, may need slight tweakage)


I've got some interesting new benchmark results here.

user= (time
 (let [m (int 1) b (double 4.0) x0 (double -0.2) y0 (double
0.1) t (double 2.0)]
   (loop [x (double 0.0) y (double 0.0) i (int 0)]
 (if ( i m)
   (let [x2 (* x x) y2 (* y y)]
 (if ( (+ x2 y2) b)
   (recur (+ (- x2 y2) x0) (+ (* t (* x y)) y0)
(unchecked-inc i))
 i))
   i
Elapsed time: 875.36796 msecs
1

A very straightforward version, and 875.36796ms/1 = 8.7536796ns.
This is on a 2.5GHz machine, so that's only about 22 native instructions per
iteration. The theoretical minimum is over 1/2 of that:

Four fmuls
Three fadds and an fsub
A floating point comparison
An integer add and an integer comparison
A branch back to the start of the loop

So we're within a factor of 2 of *native* code speeds (nevermind Java) here.

user= (time
 (let [m (int 1) b (double 4.0) x0 (double -0.2) y0 (double
0.1) t (double 2.0)]
   (loop [x (double 0.0) y (double 0.0) i m]
 (if ( i 0)
   (let [x2 (* x x) y2 (* y y)]
 (if ( (+ x2 y2) b)
   (recur (+ (- x2 y2) x0) (+ (* t (* x y)) y0)
(unchecked-dec i))
 i))
   i
Elapsed time: 3418.8542 msecs
0

Shockingly, reversing the count-up to a count-down and not changing anything
else at all makes things much, MUCH worse, about four times slower.

user= (time
 (let [m (int 1) b (double 4.0) x0 (double -0.2) y0 (double
0.1) t (double 2.0)]
   (loop [x (double 0.0) y (double 0.0) i m]
 (if (zero? i)
   i
   (let [x2 (* x x) y2 (* y y)]
 (if ( (+ x2 y2) b)
   (recur (+ (- x2 y2) x0) (+ (* t (* x y)) y0)
(unchecked-dec i))
 i))
Elapsed time: 874.9564 msecs
0

The original, at-least-half-of-C speed again.

It seems like  and zero? are as fast as each other and  much slower on
primitive ints.

user= ^#'
{:ns #Namespace clojure.core, :name , :file clojure/core.clj, :line
589, :arglists ([x] [x y] [x y  more]), :inline-arities #{2}, :inline
#core$fn__3363 clojure.core$fn__3...@b655a, :doc Returns non-nil if nums
are in monotonically increasing order,\n  otherwise false.}
user= ^#'zero?
{:ns #Namespace clojure.core, :name zero?, :file clojure/core.clj, :line
742, :arglists ([x]), :inline #core$fn__3485 clojure.core$fn__3...@7787a5,
:tag java.lang.Boolean, :doc Returns true if num is zero, else false}
user= ^#'
{:ns #Namespace clojure.core, :name , :file clojure/core.clj, :line
617, :arglists ([x] [x y] [x y  more]), :inline-arities #{2}, :inline
#core$fn__3379 clojure.core$fn__3...@51e67c, :doc Returns non-nil if nums
are in monotonically decreasing order,\n  otherwise false.}

It isn't that  isn't inlined, either.

I think the inline implemenation #core$fn__3379
clojure.core$fn__3...@51e67c of  needs to be investigated for why it is
apparently vastly slower than that of .

In the meantime, I'm not sure why Andy's code is still 3x slower than Java,
while mine runs at more than half the speed of native C. Perhaps it's a
difference in our JVMs or hardware. I'm using 1.6.0u13 -server on a 2.5GHz
Intel CPU. If Andy's using a different JVM, not using -server, or using a
CPU with fewer registers (to run as fast as it does my loop must be running
entirely in CPU registers -- there's not enough slack time between the 5ns
minimum to execute the calculations at 2.5GHz and the 9ns actual time to
make a round trip to my 7ns RAM -- but on another CPU arch with fewer
registers the loop might not fit in the registers. The bigger difference
between C and Clojure on Andy's system could then result if the JIT is
making it less register-efficient (using say one or two more) than
hand-tuned assembly or a good C optimizer, and this is making the difference

Re: How to create structure with a seq of keys

2009-08-10 Thread John Harrop
On Sun, Aug 9, 2009 at 8:55 PM, David Nolen dnolen.li...@gmail.com wrote:

 Sounds like you want apply:
 (apply fn args)


Indeed.

Since create-struct (not create-structure!) is a function, this should work.
It wouldn't work with a macro, though.

--~--~-~--~~~---~--~~
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: Commenting Code (Was: Re: Clojure as a First Language)

2009-08-10 Thread John Harrop
On Sun, Aug 9, 2009 at 12:47 PM, Lauri Pesonen lauri.peso...@iki.fi wrote:


 2009/8/8 Luc Prefontaine lprefonta...@softaddicts.ca:

  I totally agree no comments is not good at all but JavaDoc style comments
 in
  Clojure ? I pray you all, please stay away of it :

 I was quite taken by this scheme style guide recently:

 http://mumble.net/~campbell/scheme/style.txt

 While I don't agree with all the points in it, and some advice is not
 Clojure compatible (e.g. do not use square brackets and the
 CL-specific block comments), I think that the guide gave me a to think
 about.


It would be nice if Enclojure's auto-indent implemented the style guide
(with suitable Clojure modificagtions). The current indent behavior for
vectors, sets, and maps is appropriate. The current indent behavior for
lists is just to indent two levels deeper for every unclosed open
parenthesis. Better might be to indent two levels deeper for

(oper foo bar
body)

where oper is either a special form with body code as the last parameter or
a macro with an  foo final parameter; but for unquoted
(foo bar
 baz)
align with the first operand, or with the operator if the first operand is
not on the same line as the operator, and for quoted
'(foo bar
 baz)
similar to [], {}, and #{} because it's data rather than an operator and
operands. Backquote expressions should be indented as if unquoted though,
because they are probably code to be output by a macro (or, less commonly,
fed to eval):
`(foo bar
  ~baz)

I suppose I should join the enclojure google group, if there is one, and
cross-post this to it.

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-09 Thread John Harrop
On Sun, Aug 9, 2009 at 3:06 AM, Andy Fingerhut 
andy_finger...@alum.wustl.edu wrote:

 I did two runs for each version, with the only difference between them
 being replacing the (zero? i) expression in function 'dot' with a
 different expression, as indicated below.  (zero? i) is a clear winner
 in reducing run time.


That's very surprising. Were you using -server in the vm options? It seems
to me that (= 0 i) for a primitive int i ought to be very fast, compared to
a Java method call that presumably takes a Number (and so would box the
int).

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-08 Thread John Harrop
On Fri, Aug 7, 2009 at 9:19 PM, Andy Fingerhut 
andy_finger...@alum.wustl.edu wrote:

  What I suggest is
 
  (loop [zr (double 0.0)
 zi (double 0.0)
 i (int (inc iterations-remaining))]
(let [zr2 (* zr zr)
  zi2 (* zi zi)]
  (if (and (not (= 0 i)) ( (+ zr2 zi2 limit-square)))
 (recur (+ (- zr2 zi2) pr) (+ (* (* f2 zr) zi) pi) (unchecked-inc
 i))
 (whatever...
 
  * Same calculations
  * Less items in recur rebind
  * Counter is also primitive
 
  (untested, may need slight tweakage)

 Needed unchecked-dec in place of unchecked-inc, and I used (zero? i)
 instead of (= 0 i) (not sure if that makes much difference), and the
 results are much better -- the time went down to a little less than
 half of what it was before.


Try (= 0 i) or whatever. Since zero? is a function it's probably boxing the
integer, unless it's a definline rather than a defn.

http://github.com/jafingerhut/clojure-benchmarks/blob/fe10ef25ec17b77dd03f6d1ccff4f35273764f3b/RESULTS


Why post a link to a blank web page?


 Thanks!
 Andy


You're welcome.

--~--~-~--~~~---~--~~
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: Durable transactions in practice?

2009-08-08 Thread John Harrop
On Sat, Aug 8, 2009 at 2:50 AM, cody koeninger c...@koeninger.org wrote:


 Assuming people aren't patching clojure ala dave griffith's external
 transactions patch in the group files, what are people doing in
 practice to durably store the state of refs?

 Storing within a transaction and somehow ensuring your store operation
 is idempotent (not to mention reversible)?
 Sending off an agent from a transaction and not worrying about race
 conditions?
 Forgoing the use of STM in favor of locks + try / catch?

  I'm not so much asking about what particular store (RDBMS, prn to a
 file, whatever) is being used, as I am curious what kind of
 coordination is being used.


In one current project, I have a macro (transaction  body) and some
functions that create a weakly ACID file-transaction concept. A function
transaction-file is called to convert a file object into the file to
actually write, which will come back as a temp file if inside a transaction,
and add that temp file to a list the transaction maintains. The transaction
macro wraps the body with a bit of preamble code that sets up an atom used
to build this list (and whose non-nil state informs the transaction-file
function) and a post-amble that renames the original files, renames the temp
files over them, and then deletes the original files. The post-amble is NOT
in a finally block, so if an exception is thrown, the files are NOT
replaced. A cleanup thread periodically kills temporary files that are too
old.

This is entirely orthogonal to clojure's dosync.

Strengths:
* Changes to several files can be done atomically, at least as far as the
one
  Clojure thread is concerned.
* Barring the unlikely event of something going wrong during the final
renamings,
  changes to files either happen or don't happen.
* The old version is never destroyed until the new version is safely in
place with
  the old name. So if something does go pear-shaped, manual recovery is
  possible by a knowledgeable user.

Weaknesses:
* Separately changing the same file twice in a single transaction won't
work.

It would be nice to have a persistence framework in Clojure that was part of
the core and provided some degree of ACID-like safety, with some sort of
dosync-like wrapper, perhaps around arbitrary file operations, perhaps only
around some system for serializing and deserializing Clojure objects.

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-08 Thread John Harrop
On Sat, Aug 8, 2009 at 5:23 AM, Mark Engelberg mark.engelb...@gmail.comwrote:


 On Fri, Aug 7, 2009 at 5:14 PM, John Harropjharrop...@gmail.com wrote:
  (if (and (not (= 0 i)) ( (+ zr2 zi2 limit-square)))

 I believe that (zero? i) is faster than (= 0 i).


On primitive ints? Have you tested it?

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-07 Thread John Harrop
On Thu, Aug 6, 2009 at 6:57 PM, Andy Fingerhut 
andy_finger...@alum.wustl.edu wrote:

 You are correct.  I've updated that file:


 http://github.com/jafingerhut/clojure-benchmarks/blob/bb9755bdeeccae84a9b09fbf34e45f6d45d4b627/RESULTS


Could you post the Mandelbrot code you use? Because I know for a fact that
Clojure can do FP calcs as fast as native C code, given the -server vm and a
loop/recur with unboxed doubles, and my understanding of Mandelbrot is that
it's just FP calcs.

--~--~-~--~~~---~--~~
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 performance tests and clojure a little slower than Java

2009-08-07 Thread John Harrop
Your core loop seems to be:
(loop [zr (double 0.0)
 zi (double 0.0)
 zr2 (double 0.0)
 zi2 (double 0.0)
 iterations-remaining iterations-remaining]
(if (and (not (neg? iterations-remaining))
 ( (+ zr2 zi2) limit-square))
  (let [new-zi (double (+ (* (* f2 zr) zi) pi))
new-zr (double (+ (- zr2 zi2) pr))
new-zr2 (double (* new-zr new-zr))
new-zi2 (double (* new-zi new-zi))]
(recur new-zr new-zi new-zr2 new-zi2 (dec iterations-remaining)))

What I suggest is

(loop [zr (double 0.0)
   zi (double 0.0)
   i (int (inc iterations-remaining))]
  (let [zr2 (* zr zr)
zi2 (* zi zi)]
(if (and (not (= 0 i)) ( (+ zr2 zi2 limit-square)))
   (recur (+ (- zr2 zi2) pr) (+ (* (* f2 zr) zi) pi) (unchecked-inc i))
   (whatever...

* Same calculations
* Less items in recur rebind
* Counter is also primitive

(untested, may need slight tweakage)

--~--~-~--~~~---~--~~
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: Transient Data Structures

2009-08-05 Thread John Harrop
On Tue, Aug 4, 2009 at 5:50 PM, Rich Hickey richhic...@gmail.com wrote:

 On Aug 4, 4:31 pm, John Harrop jharrop...@gmail.com wrote:
  What about things like:
 
  (persistent!
(reduce
  (fn [x [i v]] (assoc! x i v))
  (transient (vec (repeat 0 (reduce max (map first
  coll-of-index-val-pairs)
  coll-of-index-val-pairs))
 

 Yes, that's completely fine intended usage, as the return value of the
 reducing fn becomes an argument to the next call.

  which is just the transientification of
 

 Nice word - transientification.


Thanks.

Of course, this makes me think of ways to possibly speed up other
operations. For example:

(defn vmap* [fun vect]
  (let [c (count vect)]
(loop [out (transient []) i 0]
  (if (= i c)
out
(recur (conj! out (fun (nth vect i))) (inc i))

(defn vmap [fun vect]
  (persistent! (vmap* fun vect)))

Vector in, vector out, conj'd up using a transient.

And, of course:

(defn vpmap [fun vect]
  (loop [out (vmap* #(future (fun %)) vect) i (dec (count vect))]
(let [o2 (assoc! out i @(nth out i))]
  (if (zero? i)
(persistent! o2)
(recur o2 (dec i)

Note that this last manipulates a transient vector in a single thread,
though other threads (from the agent pool) calculate a bunch of futures that
are stored in it. The transient vector of futures is generated using the
vmap* from above, and then the futures are replaced with their values
in-place by the loop in vpmap, before this persistentizes and returns that
vector. The future-dereferencing loop works backwards from the end of the
vector in case zero? is a quicker test than a general equality test. This is
likely on hardware that implements an equality test as a subtraction
followed by a zero test, because it eliminates the subtraction. On the other
hand, hardware with a 1-cycle equality test of 32-bit ints is plausible, as
is hardware that optimizes forward traversal of vectors, so I can't vouch
for that being an optimization. The first loop has to go forward to conj up
the output vector without reversing it, though.

--~--~-~--~~~---~--~~
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: Reflection warning: reference to field getClass can't be resolved.

2009-08-05 Thread John Harrop
On Tue, Aug 4, 2009 at 7:46 PM, Vagif Verdi vagif.ve...@gmail.com wrote:


 When reflection warning is on, i get 2 warnings on every my file:

 reference to field getClass can't be resolved.


That one is very weird, because getClass is a method of java.lang.Object. It
should always be possible to resolve that one without reflection.

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



Miscellanea prompted by a comp.lang.lisp post about Clojure

2009-08-05 Thread John Harrop
I just saw someone post a bunch of Clojure code to comp.lang.lisp one
function from which was:

(defn partition-with [pred coll]
  (loop [in coll curr [] out []]
(if (empty? in)
  (conj out curr)
  (let [obj (first in)]
(if (pred obj)
  (recur (rest in) [] (conj out curr))
  (recur (rest in) (conj curr obj) out))

This looks like it might be generally useful (and the CLL poster thought so
too); it splits a collection at items determined by the predicate, producing
a vector of vectors of items not matching the predicate:

user= (partition-with odd? [3 4 8 7 9 2 4 6])
[[] [4 8] [] [2 4 6]]

(The empty collections are from before 3 and between 7 and 9, from the look
of it.

user= (remove empty? (partition-with odd? [3 4 8 7 9 2 4 6]))
([4 8] [2 4 6])

gives what you might want instead, in some situations.)


The same CLL poster noticed that conj with two maps for arguments seems to
duplicate the functionality of merge. I've just tested this and it seems to
be true, even with key duplications:

user= (merge {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} )
{:key4 4, :key1 1, :key2 2, :key3 7}
user= (conj {:key2 2 :key3 3} {:key1 1 :key4 4 :key3 7} )
{:key4 4, :key1 1, :key2 2, :key3 7}

This makes merge appear redundant.

Further experimentation shows that there isn't even a type-safety reason to
prefer merge. It doesn't throw on vectors. In fact:

user= (merge [1 2 3] 4)
[1 2 3 4]
user= (merge '(1 2 3) 4)
(4 1 2 3)
user= (merge #{1 2 3} 8)
#{1 2 3 8}
user= (merge #{1 2 3} 3)
#{1 2 3}
user= (merge #{1 2 3} #{4 3})
#{1 2 3 #{3 4}}
user= (conj #{1 2 3} #{4 3})
#{1 2 3 #{3 4}}

so merge appears to be strictly synonymous with conj. Curiouser and
curiouser...

--~--~-~--~~~---~--~~
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: Minor macro help

2009-08-04 Thread John Harrop
Very clever, Meikel.

--~--~-~--~~~---~--~~
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: Memfn: what does it mean?

2009-08-04 Thread John Harrop
On Tue, Aug 4, 2009 at 2:22 AM, Meikel Brandmeyer m...@kotka.de wrote:


 Hi,

 On Aug 3, 10:10 pm, John Harrop jharrop...@gmail.com wrote:

  (defn and-ns
A non-short-circuiting \and\ usable in reduce etc.
([] true)
([a] a)
([a b] (and a b))
([a b  more] (reduce and-ns (and a b) more)))

 Don't think to complicated.

(reduce #(and %1 %2) coll)

 This should do the trick, no? It's still non-short-circuiting, though.


That will do the trick, but it's kind of ugly compared to just having a
symbol for the first argument to reduce.


 I think memfn is some relict like .., which pre-dates some
 of the nice additions to clojure.

#(.foo %1 %2 fixed-arg %3)


What, you mean it predates the #(...) read-macro?

I wouldn't know; I only started using Clojure when version 1.0 became
available.

--~--~-~--~~~---~--~~
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: Newbie question on using Java Libraries

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 4:16 AM, Adie adit...@gmail.com wrote:


 Good Afternoon folks,

 I am a newbie to Clojure, coming from CL, with very little Java
 background.
 I am trying to use the 'javax.persistence' libraries, but i just cant
 seem to import it properly

 for e.g
 (import '(javax.persistence Persistence)
 gives a
 java.lang.ClassNotFoundException: javax.persistence.Persistence
 (NO_SOURCE_FILE:0) error


I don't see a javax.persistence package listed at
http://java.sun.com/javase/6/docs/api/ so it apparently doesn't come with
the JDK. You probably need (and probably already have) a jar for it
(probably one of those JSR jars, given the package name). You also need (and
probably don't have) the jar on the classpath.

If you're using Eclipse or Netbeans, edit the project to add a library, then
when prompted browse to that jar. Close and restart your REPL if you had it
open, so that the change takes effect. Then try executing the code again and
it should work if the jar is present and was added to the project libraries.

If you're using emacs, then may God have mercy on your soul.

--~--~-~--~~~---~--~~
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: Memfn: what does it mean?

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 8:53 AM, Mike DeLaurentis delauren...@gmail.comwrote:


 I believe it stands for member function. From the doc string:

  Expands into code that creates a fn that expects to be passed an
  object and any args and calls the named instance method on the
  object passing the args. Use when you want to treat a Java method as
  a first-class fn.


Interestingly, it's just a very simple macro to automate wrapping the method
call in an anonymous lambda:

user= (macroexpand-1 '(memfn add x y))
(clojure.core/fn [target__4193__auto__ x y] (. target__4193__auto__ (add x
y)))

That is, basically (fn [object x y] (.add object x y)).

I'd guessed as much even before trying the above macroexpand-1 line. It was
the obvious way to implement it with no magic required. (I think you'll find
that most of the magic in Clojure is ClassLoader voodoo quite far under the
hood, and that a lot of seemingly fancy features are simply implemented as
fairly basic macros. The .add type of method call, however, does seem to
be some sort of serious mojo. (doc .add) throws an exception rather than
recognizing it as a special form or similarly, though you also get strange
errors if you try to use .add as a variable name.)

--~--~-~--~~~---~--~~
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: Memfn: what does it mean?

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 3:45 PM, Richard Newman holyg...@gmail.com wrote:


  user= (macroexpand-1 '(memfn add x y))
  (clojure.core/fn [target__4193__auto__ x y] (. target__4193__auto__
  (add x y)))
 
  That is, basically (fn [object x y] (.add object x y)).

 .add is macroexpanded into the more general dot form, as shown in the
 memfn expansion.

 user= (read-string (.foo bar))
 (.foo bar)
 user= (macroexpand-1 *1)
 (. bar foo)


So, it treats .foo in form-initial position as a macro, though not
elsewhere (so (doc .foo) does not produce Macro. and other data).

Plain . is reported as a Special Form by doc.

It is definitely interesting sometimes to poke at the guts of Clojure in the
REPL. :)

One apparent deficiency brought to light by all of this: since memfn is a
macro, it's not itself composable. Other macros where I've found this to
occasionally be a problem are and and or (where I wanted to do something
like (reduce and (map pred? coll))) but it's easy enough to make function
versions of all of them:

(defn and-ns
  A non-short-circuiting \and\ usable in reduce etc.
  ([] true)
  ([a] a)
  ([a b] (and a b))
  ([a b  more] (reduce and-ns (and a b) more)))

(defn or-ns
  A non-short-circuiting \or\ usable in reduce etc.
  ([] false)
  ([a] a)
  ([a b] (or a b))
  ([a b  more] (reduce or-ns (or a b) more)))

(defn make-memfn
  Given a quoted method name and a quoted vector of argument names, returns
a function that can be composed and that takes a target object plus the
named arguments and invokes the named method on that target with those
arguments.
  [name arg-vec]
  (eval `(fn [target# ~...@arg-vec] (. target# (~name ~...@arg-vec)

Of course, the first two don't short-circuit like their macro counterparts,
and the latter needs its arguments quoted. The latter generates:

user= (make-memfn 'add '[x y])
(clojure.core/fn [target__15__auto__ x y] (. target__15__auto__ (add x y)))

(obtained by dropping the eval from make-memfn, so it just returned the
backquoted expression; compare with memfn above).

Of course you're probably doing some serious voodoo if you are generating
memfns on the fly from run-time-determined names and argument vectors.
Metaprogramming, or making some kind of Java-object inspector, or whatever.
The function versions of and and or are much more generally useful, since
reductions over maps of predicates arise from time to time in more ordinary
situations.

--~--~-~--~~~---~--~~
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: Minor macro help

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 5:43 PM, samppi rbysam...@gmail.com wrote:

 I'm getting stuck because a-map always gets passed into my-macro
 as a symbol.

  (defmacro my-macro [a-map  forms] ; Naive implementation
`(binding ~(vec (process-a-map a-map)) ~...@forms))


Try

(defmacro my-macro [a-map  forms] ; Naive implementation
  `(binding ~(vec (process-a-map ~a-map)) ~...@forms))

If you want something included not as a symbol, precede it with a ~ (does
the same thing , does in common lisp). You already have ~...@forms which just
does the same thing, except that if forms is a list it is appended to the
list it's in rather than inserted as a single item.

If bar = (+ 2 3):

`(foo bar) = (foo bar)
`(foo ~bar) = (foo (+ 2 3))
`(foo ~...@bar) = (foo + 2 3)

Takes some getting used to, but once you master Lisp macros, it's Katie bar
the door.

--~--~-~--~~~---~--~~
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: Transient Data Structures

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 7:27 PM, CuppoJava patrickli_2...@hotmail.comwrote:


 Hi Rich,
 This is a very useful addition thanks. I personally find the O(1)
 transformation to and back most useful.

 I have a question about capturing the return values of conj! and
 assoc!.

 in this code:
 (let [v (transient [])
   v2 (conj! v 0)])

 v2 is the captured return value from conj!, which you're supposed to
 use for future operations. But what does v point to now?


The site says: Note in particular that transients are not designed to be
bashed in-place. You must capture and use the return value in the next
call.

So v is not safe to use. Probably either using it throws an exception or
else it points to a node in the implementation of v2, but not necessarily
the correct head or root node, so that using it will have questionable
effects. (Common Lisp has similar cases. Let l be a list, s the results of
calling sort on l, and examine l. It's likely to now be a tail of, but not
the entirety of, s, because it points to the same cons it always did and
sort moved that cons so it isn't the head of the list any more, while
returning the head cons. This doesn't happen with Clojure's sort because
Clojure's sort doesn't mutate; in Clojure, l stays pointing to the unsorted
list and s points to a sorted version. But these new transient mutators may
behave more like Common Lisp's sequence mutators in this regard. Rich?)

--~--~-~--~~~---~--~~
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: Minor macro help

2009-08-03 Thread John Harrop
On Mon, Aug 3, 2009 at 8:01 PM, CuppoJava patrickli_2...@hotmail.comwrote:


 You can use eval to retrieve the value of a-map when the macro is
 expanded.

 (let [value (eval a-map)]
  `(binding ~(vec (process-a-map value)) ~...@forms))

 I've programmed some substantial programs now in Clojure though, and
 I've never had to use this. Perhaps there is another way to achieve
 what you want?

 As a rule of thumb that I use, using a macro should only look like a
 syntax extension. There shouldn't be any dependance on the values of
 any of the arguments.


Eh, I hadn't noticed that; he's using process-a-map already in a ~
expression. That's the sort of thing more usually done in a helper function:

(defn binding-from-map [a-map forms]
  `(binding ~(vec (process-a-map a-map)) ~...@forms)))

Then call from a macro:

(defmacro foo [map  body]
  (binding-from-map map body))

(foo {:a 1} (fn1 arg1) (fn2 arg2 arg3))

If you really want to call the eventual macro with a non-literal map,
though, then you'll need it to eval that argument as Patrick says.

--~--~-~--~~~---~--~~
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: Idiomatic parsing of objects from several lines of a text file

2009-07-31 Thread John Harrop
On Thu, Jul 30, 2009 at 9:37 PM, Richard Newman holyg...@gmail.com wrote:

 I suppose in Clojure we could use a real arrow character, with UTF-8
 available in symbol names...


I don't know about you, but I personally prefer to only use symbols that I
can actually type. Copying and pasting from Character Map kind of interrupts
flow, if you know what I mean?

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



Bug? Definline arguments multiply evaluated.

2009-07-30 Thread John Harrop
user= (definline addsq [a b] `(+ (* ~a ~a) (* ~b ~b)))
#'hxr.clj.util/addsq
user= (addsq (do (println a evaluated) 1) 1)
a evaluated
a evaluated
2

--~--~-~--~~~---~--~~
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: Parallel garbage collection worthwhile?

2009-07-29 Thread John Harrop
On Wed, Jul 29, 2009 at 2:59 AM, Daniel Lyons fus...@storytotell.orgwrote:

 Probably it would help to try and implement a lazy
 list of the Fibonacci sequence before looking at that code, and then
 maybe try some other mathematical sequences that are a little easier
 to construct too.


Using the super-lazy-seq macro Wrexsoul posted a month or so ago, that's
dead easy:

(super-lazy-seq [a 0 b 1] (next-item b b (+ a b)))

On the other hand,

(defn fibs [] (cons 1 (cons 1 (lazy-seq (map + (fibs) (rest (fibs)))
(def fibs (memoize fibs))

works and is done with map rather than a looping-like construct. (Without
the memoize, the latter is exponential in time; with it, though, all
generated terms are retained in memory. This could be scoped, by using
(binding [fibs (memoize fibs)] (take n fibs)) or whatever whenever you
needed to do something with (part of) fibs, and returning something.
Downside: binding doesn't work well with lazy seqs. It's actually probably
easier to use the first version efficiently in a pure-functional way, even
if its less pure-functional inside. On the other hand, I'm a bit
suspicious of that macro. It seems to work for common cases, but I suspect
it will not work properly if you shadow one of its loop bindings with a let
in the loop body, as I think it doesn't care if it's the same var so long as
it has the same name when it wraps the loop vars in a deref.

(map second (iterate (fn [[a b]] [b (+ a b)]) [0 1]))

seems to work though and avoids the memory problems of the memoized
function, the exponential tendencies of the un-memoized function, AND the
super-lazy-seq macro (and even the lazy-seq macro). Interestingly, it works
identically to the super-lazy-seq macro in that both start with a pair of [a
= 0, b = 1] and transform it according to [a - b, b - (+ a b)].

In fact, there's a general correspondence between
(map #(nth % n) (iterate (fn [[a b c ... z]] [exprs]) [a0 b0 c0 ... z0]))
and
(super-lazy-seq [a a0 b b0 c c0 ... z z0] (next-item an exprs))
and I suspect the map/iterate versions to be more efficient since they avoid
atoms. (On the other hand, if the sequence is generated in a non-functional
way, such as from network I/O, super-lazy-seq seems to me to be a better fit
as long as you avoid shadowing any of its loop bindings internally.)

--~--~-~--~~~---~--~~
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: a denilling macro

2009-07-28 Thread John Harrop
On Mon, Jul 27, 2009 at 8:33 PM, nchubrich nicholas.chubr...@gmail.comwrote:

   Anyway I'd appreciate any critiques of the implementation; whether
 it's a useful thing or not; if there are more idiomatic ways of doing
 the same thing; and, if yes-no to the aforetwo, where's the best place
 to add this functionality?


Well, it won't actually work properly at run-time, and won't work with a
multiple-expression body. Try:

(defmacro i-let [bindings  body]
 (assert-args i-let
   (vector? bindings) a vector for its bindings
   (= 0 (mod (count bindings) 3)) forms by three in binding vector)
 (if (empty? bindings)
   `(let ~bindings ~body)
 `(let [nom# ~(bindings 0)
attempted-val# ~(bindings 1)
nil-val# ~(bindings 2)]
   (if (nil? attempted-val#)
(let [~nom# ~nil-val#] (i-let ~(vec (drop 3 bindings)) ~...@body))
(let [~nom# ~attempted-val#] (i-let ~(vec (drop 3 bindings))
~...@body))

though I'm somewhat dubious about it producing trees of nested lets instead
of a single let, with many copies of the body, too; why not

(defmacro i-let [bindings  body]
  (assert-args i-let
(vector? bindings) a vector for its bindings
(= 0 (mod (count bindings) 3)) forms by three in binding vector)
  `(let
 ~(vec
(reduce concat
  (map
#(list
   (first %)
   `(let [x# ~(second %)]
  (if (nil? x#)
~(second (rest %))
x#)))
(partition 3 bindings
 ~...@body))

Input:
(i-let [x (foo) 0
y (:key strct) (:key default-map)]
  (swap! foo bar baz)
  (inc x))

Output:
(let [x (let [x__1034__auto__ (foo)]
  (if (nil? x__1034__auto__)
0
x__1034__auto__))
  y (let [x__1034__auto__ (:key strct)]
  (if (nil? x__1034__auto__)
(:key default-map)
x__1034__auto__))]
  (swap! foo bar baz)
  (inc x))

Note that this just automates what you said you were too lazy to do, write
an if for every binding. This is generally how best to do macros: make them
generate the same code you'd otherwise write manually. :)

(You can test it yourself using macroexpand-1 if you want to.)

--~--~-~--~~~---~--~~
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: Newbish question. Does anyone have any example code for playing a wav sound file?

2009-07-28 Thread John Harrop
On Mon, Jul 27, 2009 at 9:00 PM, Rayne disciplera...@gmail.com wrote:


 I've googled around, and found several ways to do this in Java, but
 I've not been successful in translating the less-complex examples. I'm
 wondering, how would an experienced Clojurian go about doing this in
 Clojure?


On my system, the following works even for mp3 files and other compressed
ones, if the appropriate JavaSound plugins are installed. It should work for
plain wavs with a bare-bones Java 6/Clojure install. It blocks, so you might
want to invoke it in a separate thread/via an Agent in actual practice. (It
might also be instructive as an example of Java interop involving things
like byte buffers.)

(defn play
  Plays an audio file. Blocks until playback is complete.
  [file]
  (let [f (if (instance? java.io.File file) file (java.io.File. file))]
(with-open [aif (javax.sound.sampled.AudioSystem/getAudioInputStream f)
ais (javax.sound.sampled.AudioSystem/getAudioInputStream
  javax.sound.sampled.AudioFormat$Encoding/PCM_SIGNED
aif)]
  (let [af (.getFormat ais)]
(with-open [line (javax.sound.sampled.AudioSystem/getSourceDataLine
af)]
  (.open line af)
  (let [bufsize (.getBufferSize line)
buf (into-array Byte/TYPE (repeat bufsize (byte 0)))]
(.start line)
(loop []
  (let [br (.read ais buf 0 bufsize)]
(if-not (= -1 br)
  (do
(.write line buf 0 br)
(recur))
  (doto line (.drain) (.stop)))

--~--~-~--~~~---~--~~
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: gen-class bytecode for method implementation

2009-07-27 Thread John Harrop
On Mon, Jul 27, 2009 at 3:37 PM, Mark Addleman mark_addle...@bigfoot.comwrote:


 I have written some Clojure code to implement java.lang.CharSequence
 that is constructed with a length and an ISeq of strings.  I need this
 because I want to pass the resulting CharSequence into Java's regex
 library.  I got the thing working (thanks to the docs and some good
 examples that I found in the discussion group) and I'm trying to
 optimize it now.  I'm willing to accept the Clojure code being ~2x
 slower than the Java equivalent, but the best I can do is 10x slower.

 The code is below.  After examining the resulting bytecode, it looks
 to me that the problem is that the Clojure compiler dispatches every
 method to an IFn that is bound as part of the class initialization.
 It's a cool idea that probably saved implementation effort but I'm
 pretty sure all the boxing/unboxing of primitives is what's killing
 the performance.

 My question is:  Can someone come up with a better way of implementing
 this to avoid the performance problems?


The only way to avoid boxing and unboxing of primitives is to avoid passing
them as arguments or returning them. It *may* work if you declare the
functions inline that need to do so, but you may need to rewrite it in a
less functional style using loop/recur.

Clojure is capable of the speed you want, though; indeed, even of the speed
of hand-tuned assembly, when done right.

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



<    1   2   3   4   >