Re: My first Clojure program (and blog post about it)

2015-08-10 Thread kirby urner
 Your way works because basically you are building two extra vectors
 which are implicitly getting destructured, but that's syntactically noisy
 and also a lot of extra computational work that is unneeded.

 --


Thanks!

I cleaned it up a bunch:

https://github.com/4dsolutions/synmods/blob/master/qrays.clj

Kirby

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-10 Thread Mark Engelberg
On Sat, Aug 8, 2015 at 12:39 PM, kirby urner kirby.ur...@gmail.com wrote:


 (defrecord XYZray [OX OY OZ]
VectorOps
(norm [this] (this))


Should be (norm [this] this) not (norm [this] (this)), because the latter
will try to invoke `this` as a function.

(defn qray-to-xyzray
  [qray]
  (let [[a] [(:OA qray)]
[b] [(:OB qray)]
[c] [(:OC qray)]
[d] [(:OD qray)]
[x] [(* (/ 1 (Math/sqrt 2))(+ (- (- a b) c) d))]
[y] [(* (/ 1 (Math/sqrt 2))(- (+ (- a b) c) d))]
[z] [(* (/ 1 (Math/sqrt 2))(- (- (+ a b) c) d))]]
(XYZray. x y z)))


You have excessive, unnecessary brackets in your let clause.  Should look
like this:

(defn qray-to-xyzray
  [qray]
  (let [a (:OA qray)
b (:OB qray)
etc

Your way works because basically you are building two extra vectors which
are implicitly getting destructured, but that's syntactically noisy and
also a lot of extra computational work that is unneeded.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-08 Thread kirby urner
On Thu, Aug 6, 2015 at 2:35 PM, Mark Engelberg mark.engelb...@gmail.com
wrote:

 Right, so if you use protocols, you'd just have one name:
 add, sub, norm, len, neg
 and use for both vectors and quadrays, rather than a v-add / q-add, etc.


I have done this vis-a-vis Quadrays and XYZrays as both are types of vector
with essentially the same API.

(defprotocol VectorOps
  (add [this other])
  (sub [this other])
  (len [this])
  (neg [this])
  (norm [this]))

https://github.com/4dsolutions/synmods/blob/master/qrays.clj


 If there are things that apply only to vectors and not quadrays, you could
 make those their own protocol (or individual functions).


However I didn't take norm out of the interface though, even though it
really only applies to one of the types.

I had XYZray just return this.  Bad idea?

(defrecord XYZray [OX OY OZ]
   VectorOps
   (norm [this] (this))
   (neg [this](XYZray. (- OX) (- OY) (- OZ)))
   (len [this](Math/sqrt (+ (* OX OX)(* OY OY)(* OZ OZ
   (add [this other] (XYZray. (+ OX (:OX other))
 (+ OY (:OY other))
 (+ OZ (:OZ other
   (sub [this other](add this (neg other


 And of course, multimethods are yet another way to achieve polymorphism in
 Clojure.  Multimethods would really shine if you want to get into
 complicated mixtures of adding vectors and quadrays, etc., or dispatch on
 something other than the type (e.g., maybe pre-normalized quadrays dispatch
 to something more efficient).  Protocols (like traditional OO) can only
 dispatch on the type of the first input.


That may be next for me.

If I initialize some plain vanilla Vector with 3 coordinates, it could
recognize that as XYZ and output a vector of that type, or of either type
given they're inter-convertible.



 One other code simplification tip: you can destructure in the parameter,
 e.g., if you were to rewrite q-neg to be a plain function as opposed to a
 protocol, you could still get convenient access to the member variables by
 writing it like this:
 (defn q-neg [{:keys [OA OB OC OD]}] (-Quadray (- OA)(- OB)(- OC) (- OD)))

 http://www.john2x.com/blog/clojure-destructuring/



Before:

(defn qray-to-xyzray
  [qray]
  (let [[a] [(:OA qray)]
[b] [(:OB qray)]
[c] [(:OC qray)]
[d] [(:OD qray)]
[x] [(* (/ 1 (Math/sqrt 2))(+ (- (- a b) c) d))]
[y] [(* (/ 1 (Math/sqrt 2))(- (+ (- a b) c) d))]
[z] [(* (/ 1 (Math/sqrt 2))(- (- (+ a b) c) d))]]
(XYZray. x y z)))


After:

(I bet I could use destructuring to shorten the above quite a bit)




 On Thu, Aug 6, 2015 at 1:52 PM, kirby urner kirby.ur...@gmail.com wrote:


 Also, don't forget to explore the test framework versus global defs and
 print statements.

 --



Right, still in my queue to get to that.  Very helpful.

Kirby

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-06 Thread kirby urner


 Also, don't forget to explore the test framework versus global defs and
 print statements.

 --



Excellent feedback Mark, thank you so much!

This is exactly what I was hoping for.  I will be simplifying said code
accordingly and posting it back.

A great way to learn!

I do think I might add the same protocol to a regular XYZ Vector defrecord
type, but then that would mean changing the names maybe to v-add, v-sub
etc. v for vector.

I have intra-conversion twixt these exotic Quadray and XYZ coordinates,
already in Python.

Plus with vectors ** we expect:  angles between any two; polar coords;
scalar grow-shrink; something like dot and cross product

So I could flesh out the one protocol (inherits from Java interface I
understand) and show how both vector notations share the same API.  That
would seem an appropriate use of the syntax maybe?

Related literature:  http://www.dividedspheres.com/

Kirby


** in this implementation a vector is always tail-originating at some
place we locally define as the origin, so any to vectors will have the
same origination point, meaning a central angle is implied.  For
polyhedrons around the origin we build with Edges, each defined with two
vectors; and with Faces (sets of Edges).  A similar notion of vector (vs.
line segment) is found in
http://www.amazon.com/Elementary-Linear-Algebra-Stewart-Venit/dp/0534951902






You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/RvHQPfBKJuM/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-06 Thread Mark Engelberg
On Thu, Aug 6, 2015 at 10:39 AM, kirby urner kirby.ur...@gmail.com wrote:

 (ns test-project.quadrays)

 (defprotocol Ops
 (q-add [this other])
 (q-sub [this other])
 (q-len [this])
 (q-neg [this])
 (q-norm [this]))

 (defrecord Quadray [OA OB OC OD]
 Ops
 (q-norm [this]
 (let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
 [x] [(min a b c d)]]
 (Quadray. (- a x) (- b x) (- c x) (- d x

 (q-neg [this] (q-norm (Quadray. (- 0 (:OA this))
 (- 0 (:OB this) )
 (- 0 (:OC this))
 (- 0 (:OD this)

 (q-len [this] (let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD
 this)]
 [k] [(/ (+ a b c d) 4)]
 [t0 t1 t2 t3] [(- a k) (- b k) (- c k) (- d k)]]
 (* (Math/sqrt 2.0)
 (Math/sqrt (+ (* t0 t0) (* t1 t1) (* t2 t2) (* t3 t3))


Inside the implementation of a record definition, you can refer to all the
parts of a record more simply.
(:OA this) can just be OA and so on.
That means the `let` is also unnecessary here.

Note that `Quadray.` could be replaced by `-Quadray`.  Both forms are
acceptable, but the latter is a true function and can be passed to
higher-order functions.

Also, note that `-` can be used as a unary function.  `(- 0 x)` can just be
replaced with `(- x)`.

The larger question here is whether records/protocols are really the right
tool for the job here.  Clojure gives you a lot of ways to do a given
thing; newcomers are often attracted to records/protocols as one of the
more familiar OO-like constructs, but that doesn't mean they are always the
right fit.

Protocols are valuable for polymorphism, i.e., implementing the same
functions over several different concrete representations.  So unless you
plan to have multiple representations of Quadrays, there's no real reason
to use protocols.  And based on your naming scheme, there's absolutely no
indication that you have any intention of having these functions ever apply
to other data structures.  Remember, Clojure eschews encapsulation (no
reason for it, since everything is immutable), therefore, a function can
get exactly the same access to the so-called privileged bits.  All your
protocol definitions as written above could simply be regular functions.

A related choice is whether to implement Quadray as a record, or just a
function that builds a map, i.e.,
(defn quadray [oa ob oc od] {:oa oa :ob ob :oc oc :od od})
or if you need a type to contrast it with other structures
(defn quadray [oa ob oc od] {:tag :quadray :oa oa :ob ob :oc oc :od od})

The tradeoffs are subtle.  Records give you improved performance when
accessing the member variables, the ability to type hint the members
(which you arguably want to do here, since all the members are doubles, and
that typing the members could potentially improve your arithmetic
performance).  But records currently have a performance bug in 1.7 that
makes them slower than plain maps when used as keys in other maps or sets,
because they don't cache their hash values the way regular maps do.
Records are almost interchangeable with maps, but there are a few ways they
are not -- for example, records by default can't be used as a function of
their keys the way maps can.  Using plain maps also gives you a simpler
serialization story.

So, there's nothing really wrong with using records/protocols, but be aware
that there are other choices with other strengths/weaknesses.

Also, don't forget to explore the test framework versus global defs and
print statements.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-06 Thread Mark Engelberg
Right, so if you use protocols, you'd just have one name:
add, sub, norm, len, neg
and use for both vectors and quadrays, rather than a v-add / q-add, etc.

If there are things that apply only to vectors and not quadrays, you could
make those their own protocol (or individual functions).

And of course, multimethods are yet another way to achieve polymorphism in
Clojure.  Multimethods would really shine if you want to get into
complicated mixtures of adding vectors and quadrays, etc., or dispatch on
something other than the type (e.g., maybe pre-normalized quadrays dispatch
to something more efficient).  Protocols (like traditional OO) can only
dispatch on the type of the first input.

One other code simplification tip: you can destructure in the parameter,
e.g., if you were to rewrite q-neg to be a plain function as opposed to a
protocol, you could still get convenient access to the member variables by
writing it like this:
(defn q-neg [{:keys [OA OB OC OD]}] (-Quadray (- OA)(- OB)(- OC) (- OD)))

http://www.john2x.com/blog/clojure-destructuring/



On Thu, Aug 6, 2015 at 1:52 PM, kirby urner kirby.ur...@gmail.com wrote:


 Also, don't forget to explore the test framework versus global defs and
 print statements.

 --



 Excellent feedback Mark, thank you so much!

 This is exactly what I was hoping for.  I will be simplifying said code
 accordingly and posting it back.

 A great way to learn!

 I do think I might add the same protocol to a regular XYZ Vector defrecord
 type, but then that would mean changing the names maybe to v-add, v-sub
 etc. v for vector.

 I have intra-conversion twixt these exotic Quadray and XYZ coordinates,
 already in Python.

 Plus with vectors ** we expect:  angles between any two; polar coords;
 scalar grow-shrink; something like dot and cross product

 So I could flesh out the one protocol (inherits from Java interface I
 understand) and show how both vector notations share the same API.  That
 would seem an appropriate use of the syntax maybe?

 Related literature:  http://www.dividedspheres.com/

 Kirby


 ** in this implementation a vector is always tail-originating at some
 place we locally define as the origin, so any to vectors will have the
 same origination point, meaning a central angle is implied.  For
 polyhedrons around the origin we build with Edges, each defined with two
 vectors; and with Faces (sets of Edges).  A similar notion of vector (vs.
 line segment) is found in
 http://www.amazon.com/Elementary-Linear-Algebra-Stewart-Venit/dp/0534951902






 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/RvHQPfBKJuM/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-08-06 Thread kirby urner


On Thursday, July 30, 2015 at 6:38:11 PM UTC-7, kirby urner wrote:



 On Thu, Jul 30, 2015 at 6:14 PM, Leif wrote:

 This still seems very verbose to me.  I think it is because the 
 definition of open, opposite, and closed are implicit in the great 
 big blocks of arithmetic you are doing.  I think a useful exercise would be 
 to define edges in terms of points, and maybe faces in terms of edges and 
 an `face?` function.  Then define different properties like `open?` in 
 terms of functions on edges.


 Yes, in the ecosystem I'm coming from, edges are indeed defined by two 
 points, points being likewise vectors (in the coordinate system sense).  

 An Edge is defined by two Vectors e.g.  (def a (length (Edge v0 v1))).  
 For vectors, I sometimes use non-XYZ 4-tuples called Quadrays (check 
 Wikipedia).  


Since last week I've been studying defrecord and defprotocol.  

Again, I expect this is overly verbose, any feedback welcome.  

I posted a link to the Python version I'm working from at the end.


(cl) K. Urner, MIT License 2015
Python - Java - Clojure curriculum
2D + 3D Graphics:  Martian Math
Topic:  Quadrays
http://www.grunch.net/synergetics/quadintro.html

*https://en.wikipedia.org/wiki/Quadray_coordinates*


*Asynchronous Learning Engine (Open Source project)*


*http://controlroom.blogspot.com/2015/08/asynchronous-learning-engine-ale.html*;

(ns test-project.quadrays)

(defprotocol Ops
  (q-add [this other])
  (q-sub [this other])
  (q-len [this])
  (q-neg [this])
  (q-norm [this]))

(defrecord Quadray [OA OB OC OD]
  Ops
  (q-norm [this]
(let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
  [x] [(min a b c d)]]
  (Quadray. (- a x) (- b x) (- c x) (- d x

  (q-neg [this] (q-norm (Quadray. (- 0 (:OA this))
  (- 0 (:OB this) )
  (- 0 (:OC this))
  (- 0 (:OD this)

  (q-len [this] (let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
  [k] [(/ (+ a b c d) 4)]
  [t0 t1 t2 t3] [(- a k) (- b k) (- c k) (- d k)]]
  (* (Math/sqrt 2.0)
 (Math/sqrt (+  (* t0 t0) (* t1 t1) (* t2 t2) (* t3 t3))

  (q-add [this other]
(q-norm (Quadray. (+ (:OA this) (:OA other))
  (+ (:OB this) (:OB other))
  (+ (:OC this) (:OC other))
  (+ (:OD this) (:OD other)

  (q-sub [this other] (q-add this (q-neg other

(def v0 (Quadray. 1 0 0 0))
(def v1 (Quadray. 0 1 0 0))
(println str (q-sub v0 v1))
(println str (q-add v0 v1))
(println str (q-neg v1))
(println str (q-len v1))


Link to Python version: 
  https://mail.python.org/pipermail/edu-sig/2015-August/011291.html

Kirby




-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread Amith George

Hi,

From a cursory glance, I didn't really understand the domain, so the 
function names I used in my rewrite might seem silly. But I wanted to 
illustrate that there is a lot of repetition in your code. Also discrete 
functions (with proper names) can make the code easier to grok. 

https://gist.github.com/amithgeorge/15b1cb607c32d39b70c7

;; instead of relying on the caller to pass the edges in the right order,
;; we accept a map and process the keys in the correct order

(defn- squared-edge-values
  [edges]
  (- [:oc :oa :ob :ca :ab :bc]
   (map #(edges %1))
   (map #(* %1 %1

;; all operations on the edges are performed on the squared values.
;; the squared values are guaranteed to be in the correct order.

;; this separates out the logic specific to opposite edges and can be tested 
separately
(defn- opposite-edge-values
  [edges]
  (let [[a2 b2 c2 d2 e2 f2] (squared-edge-values edges)]
[[a2 e2 (+ a2 e2)]
 [b2 f2 (+ b2 f2)]
 [c2 d2 (+ c2 d2)]]))

(defn- closed-edge-values
  [edges]
  (let [[a2 b2 c2 d2 e2 f2] (squared-edge-values edges)]
[[a2 b2 d2]
 [d2 e2 f2]
 [b2 c2 e2]
 [a2 c2 f2]]))

(defn- open-edge-values
  [edges]
  ;; implement later
  [[0 0 0]])

(defn- compute-edge-values
  [edge-fn edges]
  (- edges
   (edge-fn)
   (map (fn [[x y z]] (* x y z)))
   (reduce +)))

(def ^:private add-opposite (partial compute-edge-values opposite-edge-values))
(def ^:private add-closed (partial compute-edge-values closed-edge-values))
(def ^:private add-open (partial compute-edge-values open-edge-values))

;; this is the public entry point.
;; the precondition ensures all the edges are present in the input

(defn volume 
  [{:keys [oa ob oc ab bc ca] :as edges}]
  {:pre [(every? #(number? %1) [oa ob oc ab bc ca])]}
  (let [opposite (add-opposite edges)
closed (add-closed edges)
open (add-open edges)]
(Math/sqrt (* (- (- open closed) opposite) 0.5


;; sample input
(defn a-mod-input
  []
  (let [a 1.0]
{:oc (* a (/ (Math/sqrt 6.0) 12.0))
 :oa (* a (/ (Math/sqrt 6.0) 4.0))
 :ob (* a (/ (Math/sqrt 2.0) 4.0))
 :ca (* a (/ (Math/sqrt 3.0) 3.0))
 :ab (/ a 2.0)
 :bc (* a (/ (Math/sqrt 3.0) 6.0))}))

(defn e-mod-input
  []
  (let [d 1.0
r (/ d 2.0)
h r]
{:oc h
 :oa 1
 :ob 1
 :ca 1
 :ab 1
 :bc 1}))

(def a-mod-volume (volume (a-mod-input)))
(def e-mod-volume (volume (e-mod-input)))


Again, the idea is to have small functions that reflect the steps you would 
normally do, as required by the domain or algo you are implementing. 

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread Mark Engelberg
Given that your functions expect a list of exactly 6 inputs, I'd be
inclined to write these as functions that take 6 inputs, rather than a
list.  That way you get a meaningful error if they pass the wrong number of
inputs.

If you do prefer to keep them as-is, you can also shorten the code by a
line by destructuring directly in the input:
(defn f [[a b c d e f :as edges]] ...)

On Thu, Jul 30, 2015 at 3:21 PM, Mark Engelberg mark.engelb...@gmail.com
wrote:

 (println (format ...)) can be rewritten as (printf ...) if you add a \n to
 your string.

 A large chunk of your computations after the definitions appear to be
 global definitions and print messages to achieve some sort of unit
 testing.  I encourage you to refactor this using clojure.test so you can
 get a feel for how unit testing is generally done in Clojure.  Those
 definitions could then be made local, and the printing is probably
 unnecessary.



-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread Leif
This still seems very verbose to me.  I think it is because the definition 
of open, opposite, and closed are implicit in the great big blocks of 
arithmetic you are doing.  I think a useful exercise would be to define 
edges in terms of points, and maybe faces in terms of edges and an `face?` 
function.  Then define different properties like `open?` in terms of 
functions on edges.

E.g. if you define a point as a keyword, and an edge as a set of 2 points:

(def o :O)
(def a :A)
(def oa #{o a})
;; ...etc...
(defn connected? [edge-1 edge-2]
  (= 1 (count (set/intersection edge-1 edge-1
(defn open? [edge-1 edge-2 edge-3] ...)

Then I think the below function will eventually become something like

(- edges
 open-triads
 ;; could give inner fn a name, too
 (map (fn [triad] (product (map edge-length triad
 sum)

The code as a whole will be more verbose, but it will be a verbosity that 
has evident meaning.

Happy Clojuring,
Leif

On Thursday, July 30, 2015 at 7:59:27 PM UTC-4, kirby urner wrote:


 Thanks to excellent feedback, I now realize my code was overly verbose, a 
 common phenomenon among beginners in many a computer language.

 As an example, the newer version replaces this:


 ===

 (ns test-project.synmods)

 (defn add-open
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [f2 a2 b2])
  (reduce * [d2 a2 c2])
  (reduce * [a2 b2 e2])
  (reduce * [c2 b2 d2])
  (reduce * [e2 c2 a2])
  (reduce * [f2 c2 b2])
  (reduce * [e2 d2 a2])
  (reduce * [b2 d2 f2])
  (reduce * [b2 e2 f2])
  (reduce * [d2 e2 c2])
  (reduce * [a2 f2 e2])
  (reduce * [d2 f2 c2])])
   )))




 ... with this:




 (defn add-open
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (+ (* f2 a2 b2)
(* d2 a2 c2)
(* a2 b2 e2)
(* c2 b2 d2)
(* e2 c2 a2)
(* f2 c2 b2)
(* e2 d2 a2)
(* b2 d2 f2)
(* b2 e2 f2)
(* d2 e2 c2)
(* a2 f2 e2)
(* d2 f2 c2))
   ))

 Much simpler!  Thank you.  I'll look into testing features.  

 In my Python version of the above, I do in fact, invoke the unittest 
 framework.

 Kirby




-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread Mark Engelberg
(println (format ...)) can be rewritten as (printf ...) if you add a \n to
your string.

A large chunk of your computations after the definitions appear to be
global definitions and print messages to achieve some sort of unit
testing.  I encourage you to refactor this using clojure.test so you can
get a feel for how unit testing is generally done in Clojure.  Those
definitions could then be made local, and the printing is probably
unnecessary.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread James Reeves
One quick suggestion is that arithmetic operations in Clojure frequently
take multiple arguments. So:

(reduce + [1 2 3])

Is equivalent to:

(+ 1 2 3)

In terms of style, variables are typically lower-case in Clojure except
when referring to a class, interface or protocol.

- James

On 30 July 2015 at 19:03, kirby urner kirby.ur...@gmail.com wrote:

 Greetings all.

 I'm new to Clojure (but not to programming) and wanted to document a first
 effort.
 The blog post:  http://controlroom.blogspot.com/2015/07/ramping-up.html

 ===

 (ns test-project.synmods)

 (defn add-open
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [f2 a2 b2])
  (reduce * [d2 a2 c2])
  (reduce * [a2 b2 e2])
  (reduce * [c2 b2 d2])
  (reduce * [e2 c2 a2])
  (reduce * [f2 c2 b2])
  (reduce * [e2 d2 a2])
  (reduce * [b2 d2 f2])
  (reduce * [b2 e2 f2])
  (reduce * [d2 e2 c2])
  (reduce * [a2 f2 e2])
  (reduce * [d2 f2 c2])])
   )))

 (defn add-closed
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [a2 b2 d2])
  (reduce * [d2 e2 f2])
  (reduce * [b2 c2 e2])
  (reduce * [a2 c2 f2])])
   )))

 (defn add-opposite
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [a2 e2 (+ a2 e2)])
  (reduce * [b2 f2 (+ b2 f2)])
  (reduce * [c2 d2 (+ c2 d2)])])
   )))

 (defn Volume
   [edges]
   (let [ open ( add-open edges)
  closed   ( add-closed edges)
  opposite ( add-opposite edges)]
  (Math/sqrt (* (- (- open closed) opposite) 0.5

 (println (format All edges D=1, Volume: %s (Volume [1.0 1.0 1.0 1.0 1.0 
 1.0]) ))

 ; A Module
 (def a 1.0)
 (def EF (* a (/ (Math/sqrt 6.0) 12.0 )))
 (def EC (* a (/ (Math/sqrt 6.0) 4.0 )))
 (def ED (* a (/ (Math/sqrt 2.0) 4.0 )))
 (def FC (* a (/ (Math/sqrt 3.0) 3.0 )))
 (def CD (/ a 2.0) )
 (def DF (* a (/ (Math/sqrt 3.0) 6.0 )))

 (def Avol (Volume [EF EC ED FC CD DF]))
 (println (format Amod volume: %s Avol))

 ; E Module
 ; Fig. 986.411A T  E Module
 ; http://www.rwgrayprojects.com/synergetics/s09/figs/f86411a.html

 (def D 1.0)
 (def R (/ D 2.0))
 (def h R)

 (def OC h)
 (def OA (* h (Math/sqrt (/ (- 5.0 (Math/sqrt 5.0)) 2.0))) )
 (def OB (* h (Math/sqrt (/ (- 9.0 (* 3 (Math/sqrt 5.0))) 2.0
 (def CA (* (/ h 2.0) (- (Math/sqrt 5.0) 1.0)))
 (def AB (* h (Math/sqrt (- 5.0 (* 2.0 (Math/sqrt 5.0))
 (def BC (* (/ h 2.0) (- 3.0 (Math/sqrt 5.0

 (def Evol (Volume [OC OA OB CA AB BC]))
 (println (format Emod volume: %s Evol))

 ; S Module
 ; Fig. 988.13A S Quanta Module Edge Lengths
 ; http://www.rwgrayprojects.com/synergetics/s09/figs/f8813a.html

 (def a D)
 (def FG (* (/ a 2.0) (*  (Math/sqrt 3.0) (Math/sqrt (- 7.0 (* 3.0 ( Math/sqrt 
 5.0) ) )
 (def FE (* a (Math/sqrt (- 7.0 (* 3.0 (Math/sqrt 5))
 (def FH (* (/ a 2.0) (- (Math/sqrt 5.0) 1.0)))
 (def GE (* (/ a 2.0) (Math/sqrt (- 7.0 (* 3.0 ( Math/sqrt 5))
 (def EH (* (/ a 2.0) (- 3.0 (Math/sqrt 5.0
 (def HG GE)

 (def Svol (Volume [FG FE FH GE EH HG]))
 (println (format Smod volume: %s Svol))

 (println (format sFactor: %s (/ Svol Evol)))


 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread kirby urner

Excellent feedback so far, I thank experienced Clojure programmers for 
giving me tips.  

I may post a next version after incorporating some of this advice.

Yes, I have much to learn!

Kirby


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread kirby urner


Thanks to excellent feedback, I now realize my code was overly verbose, a 
common phenomenon among beginners in many a computer language.

As an example, the newer version replaces this:


===

 (ns test-project.synmods)

 (defn add-open
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [f2 a2 b2])
  (reduce * [d2 a2 c2])
  (reduce * [a2 b2 e2])
  (reduce * [c2 b2 d2])
  (reduce * [e2 c2 a2])
  (reduce * [f2 c2 b2])
  (reduce * [e2 d2 a2])
  (reduce * [b2 d2 f2])
  (reduce * [b2 e2 f2])
  (reduce * [d2 e2 c2])
  (reduce * [a2 f2 e2])
  (reduce * [d2 f2 c2])])
   )))




... with this:




(defn add-open
  [edges]
  (let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(+ (* f2 a2 b2)
   (* d2 a2 c2)
   (* a2 b2 e2)
   (* c2 b2 d2)
   (* e2 c2 a2)
   (* f2 c2 b2)
   (* e2 d2 a2)
   (* b2 d2 f2)
   (* b2 e2 f2)
   (* d2 e2 c2)
   (* a2 f2 e2)
   (* d2 f2 c2))
  ))

Much simpler!  Thank you.  I'll look into testing features.  

In my Python version of the above, I do in fact, invoke the unittest framework.

Kirby


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread kirby urner
On Thu, Jul 30, 2015 at 6:14 PM, Leif leif.poor...@gmail.com wrote:

 This still seems very verbose to me.  I think it is because the definition
 of open, opposite, and closed are implicit in the great big blocks of
 arithmetic you are doing.  I think a useful exercise would be to define
 edges in terms of points, and maybe faces in terms of edges and an `face?`
 function.  Then define different properties like `open?` in terms of
 functions on edges.


Yes, in the ecosystem I'm coming from, edges are indeed defined by two
points, points being likewise vectors (in the coordinate system sense).

An Edge is defined by two Vectors e.g.  (def a (length (Edge v0 v1))).  For
vectors, I sometimes use non-XYZ 4-tuples called Quadrays (check
Wikipedia).

A Polyhedron is defined as a set of faces, going around clockwise or
counter, giving all the vectors to that face.  Vectors are tail
originating by definition i.e. their tails are all anchored at the origin.

Here's my Clojure code after some recent refactoring, minus the redundant
bits I've not changed yet.

I was 2nd powering all the six edge lengths each time inside the three
sub-functions (components of Volume) whereas really Volume should just do
that once.

That's all my let form does anymore:

(ns test-project.synmods)

(defn add-open
  [a2 b2 c2 d2 e2 f2]
  (+ (* f2 a2 b2)
 (* d2 a2 c2)
 (* a2 b2 e2)
 (* c2 b2 d2)
 (* e2 c2 a2)
 (* f2 c2 b2)
 (* e2 d2 a2)
 (* b2 d2 f2)
 (* b2 e2 f2)
 (* d2 e2 c2)
 (* a2 f2 e2)
 (* d2 f2 c2)))

(defn add-closed
  [a2 b2 c2 d2 e2 f2]
  (+ (* a2 b2 d2)(* d2 e2 f2)(* b2 c2 e2)(* a2 c2 f2)))

(defn add-opposite
   [a2 b2 c2 d2 e2 f2]
   (+ (* a2 e2 (+ a2 e2)) (* b2 f2 (+ b2 f2))(* c2 d2 (+ c2 d2

(defn Volume
   [edges]
   (let [[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (Math/sqrt (*
  (-
(- (add-open a2 b2 c2 d2 e2 f2)(add-closed a2 b2
c2 d2 e2 f2) )
(add-opposite a2 b2 c2 d2 e2 f2))
  0.5

(println (format All edges D=1, Volume: %s (Volume [1.0 1.0 1.0 1.0
1.0 1.0]) ))

; A Module
; Fig. 986.421
; http://www.rwgrayprojects.com/synergetics/s09/figs/f86421.html

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread kirby urner
On Thu, Jul 30, 2015 at 6:33 PM, Amith George strider...@gmail.com wrote:


 Hi,

 From a cursory glance, I didn't really understand the domain, so the
 function names I used in my rewrite might seem silly. But I wanted to
 illustrate that there is a lot of repetition in your code. Also discrete
 functions (with proper names) can make the code easier to grok.

 https://gist.github.com/amithgeorge/15b1cb607c32d39b70c7



Excellent!  Lots to study here.  I'm still picking up some of the basic
grammar.  Very helpful.

Thanks for taking the time to show me some ropes!

Kirby

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: My first Clojure program (and blog post about it)

2015-07-30 Thread Mark Engelberg
The do's are unnecessary.

On Thu, Jul 30, 2015 at 2:50 PM, James Reeves ja...@booleanknot.com wrote:

 One quick suggestion is that arithmetic operations in Clojure frequently
 take multiple arguments. So:

 (reduce + [1 2 3])

 Is equivalent to:

 (+ 1 2 3)

 In terms of style, variables are typically lower-case in Clojure except
 when referring to a class, interface or protocol.

 - James

 On 30 July 2015 at 19:03, kirby urner kirby.ur...@gmail.com wrote:

 Greetings all.

 I'm new to Clojure (but not to programming) and wanted to document a
 first effort.
 The blog post:  http://controlroom.blogspot.com/2015/07/ramping-up.html

 ===

 (ns test-project.synmods)

 (defn add-open
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [f2 a2 b2])
  (reduce * [d2 a2 c2])
  (reduce * [a2 b2 e2])
  (reduce * [c2 b2 d2])
  (reduce * [e2 c2 a2])
  (reduce * [f2 c2 b2])
  (reduce * [e2 d2 a2])
  (reduce * [b2 d2 f2])
  (reduce * [b2 e2 f2])
  (reduce * [d2 e2 c2])
  (reduce * [a2 f2 e2])
  (reduce * [d2 f2 c2])])
   )))

 (defn add-closed
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [a2 b2 d2])
  (reduce * [d2 e2 f2])
  (reduce * [b2 c2 e2])
  (reduce * [a2 c2 f2])])
   )))

 (defn add-opposite
   [edges]
   (let [[a b c d e f] edges
 [a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
 (do
   (reduce + [
  (reduce * [a2 e2 (+ a2 e2)])
  (reduce * [b2 f2 (+ b2 f2)])
  (reduce * [c2 d2 (+ c2 d2)])])
   )))

 (defn Volume
   [edges]
   (let [ open ( add-open edges)
  closed   ( add-closed edges)
  opposite ( add-opposite edges)]
  (Math/sqrt (* (- (- open closed) opposite) 0.5

 (println (format All edges D=1, Volume: %s (Volume [1.0 1.0 1.0 1.0 1.0 
 1.0]) ))

 ; A Module
 (def a 1.0)
 (def EF (* a (/ (Math/sqrt 6.0) 12.0 )))
 (def EC (* a (/ (Math/sqrt 6.0) 4.0 )))
 (def ED (* a (/ (Math/sqrt 2.0) 4.0 )))
 (def FC (* a (/ (Math/sqrt 3.0) 3.0 )))
 (def CD (/ a 2.0) )
 (def DF (* a (/ (Math/sqrt 3.0) 6.0 )))

 (def Avol (Volume [EF EC ED FC CD DF]))
 (println (format Amod volume: %s Avol))

 ; E Module
 ; Fig. 986.411A T  E Module
 ; http://www.rwgrayprojects.com/synergetics/s09/figs/f86411a.html

 (def D 1.0)
 (def R (/ D 2.0))
 (def h R)

 (def OC h)
 (def OA (* h (Math/sqrt (/ (- 5.0 (Math/sqrt 5.0)) 2.0))) )
 (def OB (* h (Math/sqrt (/ (- 9.0 (* 3 (Math/sqrt 5.0))) 2.0
 (def CA (* (/ h 2.0) (- (Math/sqrt 5.0) 1.0)))
 (def AB (* h (Math/sqrt (- 5.0 (* 2.0 (Math/sqrt 5.0))
 (def BC (* (/ h 2.0) (- 3.0 (Math/sqrt 5.0

 (def Evol (Volume [OC OA OB CA AB BC]))
 (println (format Emod volume: %s Evol))

 ; S Module
 ; Fig. 988.13A S Quanta Module Edge Lengths
 ; http://www.rwgrayprojects.com/synergetics/s09/figs/f8813a.html

 (def a D)
 (def FG (* (/ a 2.0) (*  (Math/sqrt 3.0) (Math/sqrt (- 7.0 (* 3.0 ( 
 Math/sqrt 5.0) ) )
 (def FE (* a (Math/sqrt (- 7.0 (* 3.0 (Math/sqrt 5))
 (def FH (* (/ a 2.0) (- (Math/sqrt 5.0) 1.0)))
 (def GE (* (/ a 2.0) (Math/sqrt (- 7.0 (* 3.0 ( Math/sqrt 5))
 (def EH (* (/ a 2.0) (- 3.0 (Math/sqrt 5.0
 (def HG GE)

 (def Svol (Volume [FG FE FH GE EH HG]))
 (println (format Smod volume: %s Svol))

 (println (format sFactor: %s (/ Svol Evol)))


 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
You received this message because you are