Re: (= '(java.lang.String) (list java.lang.String)) = false ?

2013-11-10 Thread Timo Mihaljov
On 10.11.2013 14:03, Dave Tenny wrote:
 I don't understand why these things aren't equal.
 
 user= (= (list java.lang.String) (list (class abc)))
 true
 user= (= '(java.lang.String) (list (class abc)))
 false
 user= (type '(java.lang.String))
 clojure.lang.PersistentList
 user= (type (list java.lang.String))
 clojure.lang.PersistentList
 
 user= (list java.lang.String)
 (java.lang.String)
 user= '(java.lang.String)
 (java.lang.String)
 user= (= *1 *2)
 false
 
 
 What am I missing?

user= (type (first (list java.lang.String)))
java.lang.Class
user= (type (first '(java.lang.String)))
clojure.lang.Symbol

-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: Counterclockwise

2013-09-07 Thread Timo Mihaljov
On 07.09.2013 11:24, Josh Kamau wrote:
 Please allow me to hijack the thread and ask:
 
 Does Counterclockwise allow slurping and barfing? like in emacs ? 

Yes. See
http://code.google.com/p/counterclockwise/wiki/EditorKeyBindingsFeatures

-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: Counterclockwise

2013-09-07 Thread Timo Mihaljov
On 07.09.2013 14:02, Josh Kamau wrote:
 I am unable to use slurp . I am using latest stable version. 
 
 does *Ctrl+) S*  mean pressing Ctrl+Shift+)+S together ? Shift so that
 i pick ) and not 9 and so that S is in caps. 

) is above 0 on my keyboard, so I can trigger the Slurp Right action
like this: press Ctrl, Shift, and 0 simultaneously, release everything,
press s.

-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: Help to morph this imperative snippet into a functional one

2013-08-19 Thread Timo Mihaljov
On 18.08.2013 16:51, Hussein B. wrote:
 Would you please help me transforming this imperative code into
 functional one?
 
 The code is a typical snippet in imperative style. A lot of mutations
 that I don't even know how to start morphing it to Clojure.
 
 class Container {
   MapString, Container children;
   String letter;
   ListString value;
 }
 
 void insert(Container container, String letters, String value) {
   
   for (int i = 0; i  letters.length; i++) {
 
 String letter = new String(letters.chatAt[i]);
 
 if (container.children.get(letter) != null) {
   container = container.children.get(letter);
 } else {
   MapContainer childContainer = new HashMap();
   container.children.put(letter, childContainer);
   container = container.children.get(letter);
 }
 
if (i == letters.length() - 1) {
  container.values.add(value);
  break;
}
 
 } 

(You don't provide example inputs and outputs for the method, so I may
have misunderstood the code. If that's the case please disregard the
next paragraph.)

This example may be to artificial to be translated into Clojure. What
use is it to store strings in a tree keyed by the string's characters?
If you know the path to the string, you already know the string itself,
and you don't need the tree at all!

It is rarely a good idea to directly translate code from one language
into a much different one. It may be done, but the end result will not
be pretty and it certainly won't be idiomatic. I'm sure you'll get much
more helpful responses if you ask a question of the form I need to
solve this problem – how can I do it in Clojure?

If what you want is to manipulate trees in a purely functional way, you
might want to check out the Zipper data structure. [1] You can find it
in Clojure's standard library in the namespace `clojure.zip`. [2]

[1]
http://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf
[2] http://richhickey.github.io/clojure/clojure.zip-api.html

Hope this helps,
-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: Help to morph this imperative snippet into a functional one

2013-08-19 Thread Timo Mihaljov
On 19.08.2013 20:27, Timo Mihaljov wrote:
 This example may be to artificial to be translated into Clojure. What
 use is it to store strings in a tree keyed by the string's characters?
 If you know the path to the string, you already know the string itself,
 and you don't need the tree at all!

Aaand of course I misread the code... I got `letters` and `value` mixed
up. Sorry about the noise!

-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: vec to map with consolidated vals

2013-08-18 Thread Timo Mihaljov
On 17.08.2013 08:40, David Chelimsky wrote:
 Which led me to this:
 
 (defn to-consolidated-map [parts]
   (apply merge-with + (map (partial apply hash-map) parts)))

This is exactly what I came up with after reading your first message.
Apparently Jay Fields took the same approach. I think it's fair to say
that this is the idiomatic solution, now that three people have come to
the same result independently. :)

-- 
Timo

-- 
-- 
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/groups/opt_out.


Re: filter with a sequence of maps not working

2013-08-07 Thread Timo Mihaljov
On 07.08.2013 10:58, Tilak Thapa wrote:
 (defn get-data 
   [ attrs]
   (let [grps data]
 (if (empty? attrs)
   grps
   (map #(select-keys % attrs) grps
 
 (filter #(= (% :id) 7) (get-data :id :b))
 
 Why above expression works but same expression wrapped as function
 (below) does not work?
 
 (defn get-data-by-id [id  attrs]
   always pass :id attribute
 (filter #(= (:id %) id) (get-data attrs)))
 
 (get-data-by-id 3) ;; returns () this is probably ok (?) since :id key
 is not available
 (get-data-by-id 3 :id :b) ;; returns () but why this does not work?

`get-data-by-id` passes one argument to `get-data`: a sequence of
attributes. `get-data-by-id` expects one argument per attribute. Instead
of `(get-data attrs)`, use `(apply get-data attrs)`.

See http://clojuredocs.org/clojure_core/clojure.core/apply for examples
demonstrating the use of `apply`.

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: distinction of defrecord instances in sorted-set-by does not work

2013-07-25 Thread Timo Mihaljov
On 25.07.2013 11:19, gixxi wrote:
 Consider the following record definition, a respective record instance
 as well as a sorted tree set with a custom comparator sorting first the
 :visited property and the by the :dist property of the record.
 
 (defrecord RDistance
   [node dist visited])
 
 (def d (RDistance. foo 1 0))
 
 (def tree (sorted-set-by (comparator (juxt :visited :dist)) d))
 
 
 I expect conj d again to the set would change the set, but doing so in
 the repl results in the set containing two equal elements
 
 user= (conj tree d)
 #{#user.RDistance{:node foo, :dist 1, :visited 0}
 #user.RDistance{:node foo, :dist 1, :visited 0}}
 
 What is the problem?

The argument to `comparator` should be a function of two arguments that
returns a boolean value:
http://clojuredocs.org/clojure_core/1.2.0/clojure.core/comparator

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: map from list of maps

2013-07-25 Thread Timo Mihaljov
On 26.07.2013 00:34, Brian Craft wrote:
 Is there a better way to do this, making a map of certain keys from a
 list of maps?
 
 (apply hash-map (mapcat (fn [x] [(x :a) (x :b)]) [{:a blah :b ack}
 {:a red :b blue}]))
 {red blue, blah ack}

Here's another way:

(let [xs [{:a blah, :b ack} {:a red, :b blue}]]
  (zipmap (map :a xs) (map :b xs)))
;= {red blue, blah ack}

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: Not using dependency injection - how do I share services around?

2013-05-10 Thread Timo Mihaljov
On 10.05.2013 14:04, Colin Yates wrote:
  2) to provide a 'get-ds' accessor which returns a new instance and rely
 on passing that service along to every function that needs it?

For what it's worth, some people in the OO community, most notably Nat
Pryce and Steve Freeman of Growing Object-Oriented Software[1] fame,
advocate[2][3] this approach over using an IoC container.

 Option 2 means functions are still pure, but how do you prevent huge
 lists of services - i.e. if func-a calls func-b which calls func-c and
 func-c needs service-a then func-a and func-b need to access service-a.
  Yuck.  It also means the main entry point to my application needs to
 assemble all of these services up in one go.

Here's the punchline from [3]:

If I later find that I can’t get access to some component that I
think I need, that’s not necessarily a bad thing. It’s telling me
that I’m introducing a new dependency and sometimes that’s a hint
that a component is in the wrong place, or that I’m trying to use
it from the wrong place. The coding bump is a design feedback
mechanism that I miss when I can just pull objects out of a
container. If I do a good job, I should find that, most of the
time, I have just the right components at the time that I need
them.

[1] http://www.growing-object-oriented-software.com/
[2] http://www.natpryce.com/articles/000783.html
[3]
http://www.higherorderlogic.com/2011/07/is-dependency-injection-like-facebook/

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: Struggling with encapsulation

2013-05-10 Thread Timo Mihaljov
On 10.05.2013 14:44, John D. Hume wrote:
 Assume a queue is your only state and `add` and `clear` are your private
 fns that take a queue as first argument.
 
 (defn new-scheduler []
   (let [queue (...)]
 {:add (partial add queue)
  :clear (partial clear queue)}))
 
 There are several disadvantages to this, however. The biggest in my book
 is that it achieves your goal, and you're limited in the same way your
 users are. You can't add behavior to an already created scheduler
 (unless it's built on adding and clearing). Furthermore, if you
 dynamically recompile `add` or `clear`, it won't change the behavior of
 an already created scheduler, since partial has the fns, not the symbols
 or vars that point at them. (These same disadvantages apply to a reified
 protocol.)

You can make dynamic recompilation work by referring to the vars and not
the functions:

{:add (partial #'add queue)
 :clear (partial #'clear queue)}

This works because vars implement `IFn` by delegating to the function
they contain.

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: idiomatic way to force evaluation of a lazy operation

2013-05-04 Thread Timo Mihaljov
On 04.05.2013 12:16, Korny Sietsma wrote:
 What's the idiomatic way to avoid this?  The options seem to be either
 to use
  (doall (map parse-record records))
 or (mapv parse-record records)
 
 Is either of these better?  The latter is simpler, the former (to me)
 expresses that you are deliberately forcing non-laziness.  Or is there
 some other alternative?

`doall` is idiomatic. As you said, `mapv` tells the reader that you need
the result to be a vector (you don't) while leaving implicit the fact
that you want to force the evaluation of the sequence, so it's confusing
in two ways.

If you don't care about the return values of the `save-result!` calls,
the best way is to use `doseq` to iterate over the records:

(defn parse-and-store [raw-data]
  (try
(save-audit-data! raw-data)
(let [records (split-records raw-data)
  results (map parse-record records)]
  (doseq [result results]
(save-result! result)))
  (catch Exception e
(save-error-data! raw-data e

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: idiomatic way to force evaluation of a lazy operation

2013-05-04 Thread Timo Mihaljov
On 04.05.2013 13:01, Korny Sietsma wrote:
 Thanks - I thought doall was probably better than mapv.
 
 Incidentally, doseq won't work - if the 5th result throws an exception
 during parsing, results 1-4 will still be saved, whereas I want the
 whole operation to abort without saving anything.

Ah right, I didn't think of that. I'd still go with `doseq` for the
saving (otherwise you'll build up a result collection just to throw it
away), just wrap the first `map parse-record` in a `doall`.

-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: is intellij idea a good ide for clojure development?

2013-01-29 Thread Timo Mihaljov
On 29.01.2013 16:32, Jay Fields wrote:
 On Tue, Jan 29, 2013 at 9:28 AM, Feng Shen shen...@gmail.com wrote:
 I have programming Clojure for almost 2 years, for a living.

 
 This is probably an important part of what answer the OP is looking
 for. When I was doing Clojure for about 10% of my job IntelliJ was
 fine. Now that it's 90% of my job, I wouldn't be able to give up emacs
 go back to IntelliJ.
 
 If you're just looking at Clojure as a hobby and you already know
 IntelliJ, I wouldn't recommend switching. However, if you're going to
 be programming Clojure almost all of the time, I think emacs is the
 superior choice.
 

For what it's worth, I switched from Emacs to Eclipse and
Counterclockwise for Clojure programming. Laurent's done an excellent
job with it, and I even prefer his take on paredit over Emacs's
original. I still use Emacs for everything else, but for Clojure I find
Counterclockwise to be the superior choice.


-- 
Timo

-- 
-- 
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/groups/opt_out.




Re: Need ideas for carving project into namespaces

2012-12-14 Thread Timo Mihaljov


On Thursday, December 13, 2012 11:43:48 PM UTC+2, puzzler wrote:

 On Thu, Dec 13, 2012 at 1:31 PM, Timo Mihaljov 
 ti...@mihaljov.infojavascript:
  wrote:

 (ns example.patron
   The patron doesn't have an artistic vision (that's the artist's job),
 nor does it know how to talk to a graphics API (that's what the canvases
 are for). What it *does* know is how many triangles and squares we can
 afford, and where we want them drawn.
   (:require [example.artist :refer [create-masterpiece]
  example.canvas :refer [make-canvas]]))

 (defn commision-a-masterpiece []
   (create-masterpiece (make-canvas) 500 1000))


 I like this idea of using multimethods to send information from the 
 concrete implementations back to the constructor in the core.

 But how do the concrete implementations ever get loaded?

 For example, if you start an empty repl and send the example.patron file 
 to the repl, none of the concrete implementations will get loaded, so 
 make-canvas will fail.  Same thing if, for example, you made 
 commission-a-masterpiece into the main function and compiled the whole 
 thing into an executable jar.

 How do you get around this?


You are right, I didn't think this through.

Frankly, after sleeping over it, I think that the multimethod trick wasn't 
a good idea. If your users know which implementation they want, they can 
just as well instantiate it themselves. And if the factory contains some 
logic for choosing the correct implementation, it necessarily operates on a 
closed set of implementations, and shouldn't live in a namespace that's all 
about the *protocol* and thus about *all the implementations*.

I think that the difficulty of partitioning code into namespaces is a 
design smell warning us of conflated responsibilities. The powerful 
namespace wrangling tools, such as immigrate, deal with the symptoms and 
not the cause. We should strive to have cohesive namespaces with clear 
acyclic dependencies, and we can reach that goal by applying the Single 
Responsibility Principle to namespace design. Here's another stab at the 
namespace partitioning, this time without a factory function and assuming 
there's a need for automatic, intelligent selection of a protocol 
implementation.

- canvas: Protocol definition, functions that operate on any protocol 
implementation. No dependencies.
- svg-canvas: Protocol implementation. Depends on canvas.
- png-canvas: Protocol implementation. Depends on canvas.
- canvas-selection: Automatic selection of a canvas from a known, closed 
set of canvases. Depends on svg-canvas and png-canvas.
- artist: Draws pictures. Depends on canvas.
- patron: Commisions pictures from the artist. Depends on artist. May 
depend on either canvas-selection or one of the concrete canvas 
implementations.

With this architecture there are no cyclic dependencies, and the users are 
free to choose between automatic canvas selection, one of the predefined 
canvas implementations, or a canvas implementation of their own.

--
Timo

-- 
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: Need ideas for carving project into namespaces

2012-12-13 Thread Timo Mihaljov
On 12.12.2012 02:16, Mark Engelberg wrote:


Hi Mark,

Here's my take on the problem. I hope you can adapt it to your situation.

(ns example.canvas
  A canvas is an abstract interface to a graphics API. The canvas
namespace does not build new functionality on top of the APIs, that's a
job for another namespace.)

(defprotocol Canvas
  (draw-triangle [canvas point-a point-b point-c])
  (draw-circle [canvas position size]))

(defmulti make-canvas-of-type (fn [type] type))

(defn make-canvas
  ([] (make-canvas-of-type :svg))
  ([type] (make-canvas-of-type type)))

;---

(ns example.svg-canvas
  A canvas that produces SVG images.
  (:import example.canvas.Canvas)
  (:require [example.canvas :refer [make-canvas-of-type]]))

(defmethod make-canvas-of-type :svg [_]
  (reify Canvas
(comment ...)))

;---

(ns example.png-canvas
  A canvas that produces PNG images.
  (:import example.canvas.Canvas)
  (:require [example.canvas :refer [make-canvas-of-type]]))

(defmethod make-canvas-of-type :png [_]
  (reify Canvas
(comment ...)))

;---

(ns example.artist
  The artist uses a canvas to provide advanced rendering operations. It
can work with any canvas you give it, so it doesn't care what kind of
different canvases there are.
  (:require [example.canvas :refer [draw-triangle draw-square]]))

(defn create-masterpiece [canvas triangle-budget circle-budget]
  Bigger budgets = better art!
  (comment
(draw-triangle ...)
(draw-circle ...)))

;---

(ns example.patron
  The patron doesn't have an artistic vision (that's the artist's job),
nor does it know how to talk to a graphics API (that's what the canvases
are for). What it *does* know is how many triangles and squares we can
afford, and where we want them drawn.
  (:require [example.artist :refer [create-masterpiece]
 example.canvas :refer [make-canvas]]))

(defn commision-a-masterpiece []
  (create-masterpiece (make-canvas) 500 1000))


-- 
Timo

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

2012-09-26 Thread Timo Mihaljov
On 24.09.2012 13:04, Mond Ray wrote:
 user= wish-lists
 [{:name WL1, :items [{:name Item 1, :cost 20.0} {:name Item 2,
 :cost 40.0}]} {:name WL2, :items [{:name Wiggle 1, :cost 20.0}
 {:name Wiggle 2, :cost 40.0} [:name Item 3 :cost 10.0]]}]

 user= (assoc-in wish-lists [:name WL1] [:name WL1 :items new-wi])
 IllegalArgumentException Key must be integer
 clojure.lang.APersistentVector.assoc (APersistentVector.java:312)

`assoc-in` navigates nested data structures by keys. Like George said,
vectors' keys are integer indices, so you'd have to use `[0]` as the
path to refer to the first wish list. To navigate the data structure
using list names, change your `wish-lists` structure into a map with the
names as keys.

(def wish-lists {WL1 [{:name Item 1, :cost 20.0}
{:name Item 2, :cost 40.0}]
 WL2 [{:name Wiggle 1, :cost 20.0}
{:name Wiggle 2, :cost 40.0}]})

`assoc-in` is for adding new key-value pairs to a map, so it isn't quite
what you need to append to the wish list vector. There's a more generic
function called `update-in`, which takes a function to update the thing
at the end of the path. `conj` appends items to a vector, so that's what
you should use as the update function.

(update-in wish-lists [WL1] conj {:name Item 3 :cost 10.0})
;= {WL1 [{:name Item 1, :cost 20.0}
   {:name Item 2, :cost 40.0}
   {:name Item 3, :cost 10.0}]
WL2 [{:name Wiggle 1, :cost 20.0}
   {:name Wiggle 2, :cost 40.0}]}

Hope this helps,
-- 
Timo

-- 
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: Behavior of (eval) in different namespaces

2012-09-25 Thread Timo Mihaljov
On 25.09.2012 23:58, Alex Dowad wrote:
 Does anyone know what's going on here?
 
 user= (let [a 1] (eval 'a))
 1
 user= (ns another-ns)
 nil
 another-ns= (let [a 1] (eval 'a))
 CompilerException java.lang.RuntimeException: Unable to resolve symbol:
 a in this context, compiling:(NO_SOURCE_PATH:41) 

I don't see this behavior on Clojure 1.4.0

user= (let [a 1] (eval 'a))
CompilerException java.lang.RuntimeException: Unable to resolve symbol:
a in this context, compiling:(NO_SOURCE_PATH:1)

-- 
Timo

-- 
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: Lightweight lib/way to strip html from text

2012-09-10 Thread Timo Mihaljov
On 06.09.2012 20:41, jamieorc wrote:
 Hey all, I'm looking for a lightweight way to strip html from a long
 String of text and leave just the text. I've come across JSoup, but at
 over 300kb for the lib, not quite lightweight. 
 
 Suggestions?

I've found Jericho HTML Parser to be fast, robust, and well documented:
http://jericho.htmlparser.net/docs/index.html

Its TextExtractor class seems to do exactly what you need:
http://jericho.htmlparser.net/docs/javadoc/net/htmlparser/jericho/TextExtractor.html
http://jericho.htmlparser.net/samples/console/src/ExtractText.java

-- 
Timo

-- 
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: understanding data structures, and other low-level stuff

2012-03-20 Thread Timo Mihaljov
On 03/15/2012 09:15 PM, Nic Long wrote:
 So I guess I'm asking whether anyone can recommend some good primers
 on data structures, both as they relate to Clojure, but also how they
 work in the fundamentals - e.g. what exactly is the classic model of
 an 'array' and how does it work, etc. I have read the various
 performance commitments for the data-types in Clojure on the .org site
 but even things like Big O notation are still pretty new to me.
 
 I'm sure this stuff is pretty basic for many, but I don't know it and
 would like to!
 
 I'm not afraid of some heavy reading; I'd rather get a really deep and
 solid grasp of the fundamentals, then a quick surface-level solution.
 If I'm to develop as a programmer I feel like I need to get looking
 under the hood as it were, even though I can get by in PHP (for the
 most part anyway) without this kind of understanding.

I can't recommend Sedgewick and Wayne's Algorithms [1] enough. It's not
heavy reading at all; I'm amazed at how readable the book is considering
the subject matter. In addition to the great writing the algorithms are
presented as Java source code, and their operation is visualized, so you
have three ways of looking at each algorithm, which really helps to
understand them. The book is also excellently structured, only
introducing a handful of new concepts at a time, so reading it cover to
cover you will very rarely feel out of your depth.

[1] http://amzn.com/032157351X

-- 
Timo

-- 
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: (OTP slightly) - ensuring assumptions about structure of function arguments in dynamic languages

2012-01-30 Thread Timo Mihaljov
As I understand the problem in your example, you do have a definition
for what an Insurable is, but it's implicit: there's no way to check
whether an object is insurable and thus no way to check which parts of
the code break when the notion of being Insurable changes. Luckily
Clojure provides us with the tools needed to make the definition
explicit.

In your Java example you used an interface to define what an Insurable
is. In Clojure you can do the same with a protocol:

(defprotocol Insurable
  (cost-to-replace-with-new [insurable]))

(def insurable? (partial satisfies? Insurable))

Whenever you expect to receive an insurable, you can use a
precondition to make this assumption explicit, like BG and Meikel
suggested:

(defn calculate-insurance [ insurables]
  {:pre [(every? insurable? insurables)]}
  ...)

Note that the Insurable objects are completely abstract; we don't know
or care what kind of data structure are used to implement them. This
means that we can't build valid Insurables by accident, like you did
in your example by calling FuncA to FuncE, but that's a *good* thing,
because data structures built like that are very brittle, as you
noted.

To wrap up the example, here are a two very different implementations
of Insurable. Note how everything is modeled in terms of domain
concepts instead of maps with keys :x, :y and :z. We manipulate the
data structures with completely normal Clojure code, but keep the
knowledge of those data structures in one place only instead of
spreading it all over the codebase. This makes the code much more
robust and amenable to change.

(defn make-simple-insurable [cost]
  {:post [(insurable? %)]}
  (reify Insurable
(cost-to-replace-with-new [_]
  cost)))

(defrecord CompositeInsurable [parts]
  Insurable
  (cost-to-replace-with-new [composite-insurable]
(- (:parts composite-insurable)
 (map cost-to-replace-with-new)
 (reduce +

(defn make-composite-insurable [ parts]
  {:pre [(every? insurable? parts)]
   :post [(insurable? %)]}
  (CompositeInsurable. parts))

--
Timo

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


Re: Leiningen and Cake

2011-12-14 Thread Timo Mihaljov

On 12/14/2011 06:37 PM, Timothy Washington wrote:

1) The first is being able to pass many tasks to lein. So I would prefer
A. instead of B.

  * A) lein clean deps
  * B) lein clean  lein deps



You can chain commands by separating them with a comma:

lein clean, deps

--
Timo

--
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: Recreate a hierarchy

2011-05-05 Thread Timo Mihaljov
On Thu, May 05, 2011 at 05:40:02AM -0700, Steffen wrote:
 Hello,
 
 I'm trying to come up with a way to recreate a directory hierarchy. Entries
 within zip archives are just flat strings like top/level/file1, but I would
 like to operate on them hierarchically. So my problem could be stated as:
 If
 
   (restore-hierarchy [[top level file1] [top level file2] [top
 level2 file3]])
 
 returns
 
   {top {level (file1 file2), level2 (file3)}}
 
  what does a nice definition of #'restore-hierarchy look like? Sadly my own
 attempts to hack it are too embarrassing to post them here...

Here's my version using `clojure.contrib.map-utils/deep-merge-with`:

(use '[clojure.contrib.map-utils
   :only [deep-merge-with]])

(defn file-path [[first  rest]]
  (if rest
{first (file-path rest)}
first))

(defn restore-hierarchy [x]
  (- x
   (map file-path)
   (apply deep-merge-with list)))

Syntax highlighted: https://gist.github.com/957202

--
Timo

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


Re: better error messages smaller stack traces

2011-02-17 Thread Timo Mihaljov
On Tue, Feb 08, 2011 at 09:01:38AM -0500, Stuart Halloway wrote:
 Please let us know when you get a misleading error message from a
 macroexpansion, so we can make it better. Or contribute a patch along the 
 lines
 of [2].

Here's another error message that really threw me off for a while.

I have some code that looks like this:

(let [[x y] (nth @my-atom z)]
  ...)

Which occasionally failed with:

java.lang.UnsupportedOperationException: nth not supported on this type: 
Float
at clojure.lang.RT.nthFrom(RT.java:815) ~[clojure-1.2.0.jar:na]
at clojure.lang.RT.nth(RT.java:765) ~[clojure-1.2.0.jar:na]

I tried to figure out how a single float could have ended up in that
atom and why I couldn't catch it by checking for `(coll? @my-atom)`.
After a while I found out that `@my-atom` indeed contained a
collection -- a collection of floats -- and that the exception was
thrown by the destructuring.

An error message something like this would have been much more helpful:

Can't destructure `(nth @my-atom z)` to `[x y]`: expected a
collection with 2 or more items but got `Float`.

--
Timo

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


Re: better error messages smaller stack traces

2011-02-14 Thread Timo Mihaljov
On Tue, Feb 08, 2011 at 09:01:38AM -0500, Stuart Halloway wrote:
 Please let us know when you get a misleading error message from a
 macroexpansion, so we can make it better. Or contribute a patch along the 
 lines
 of [2].

Here's a misleading lack of an error message:

(defn foo [x]
  {:pre (odd? x)}
  x)

The code may look fine at a glance, but the precondition is not
wrapped in a seq, so the actual preconditions become checks for
truthiness of `odd?` and `x`.

Maybe precondition forms should be required to be vectors, so that
function call forms can't be mistaken for lists of preconditions?

--
Timo

-- 
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: Images in autodoc?

2010-10-26 Thread Timo Mihaljov
On Tue, Oct 26, 2010 at 02:15:21PM -0400, Andrew Gwozdziewycz wrote:
 Areas likely to include gobbledegook:
 [...]
 2. links (internal. for external links, just use fully qualified URI)

Internal links could be easily handled by trying to resolve all `code
blocks` with ns-resolve in the namespace containing the docstring. If
the block resolves to a var, make it a link. No gobbledegook needed.
(In practice you'd need a slightly more complicated algorithm to
handle cases where e.g. a parameter shadows an existing var.)

If you wanted to get real fancy, you could even check if the code
block is a list, and then resolve each symbol inside the list, so
that, for example, resolve's docstring would look like this at the
REPL:

user= (doc resolve)
-
clojure.core/resolve
([sym])
  same as `(ns-resolve *ns* sym)`

But in the HTML documentation `ns-resolve` and `*ns*` would be
hyperlinks.

--
Timo

-- 
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: Game development in Clojure

2010-08-20 Thread Timo Mihaljov
On Mon, Aug 16, 2010 at 03:43:11AM -0700, Mike Anderson wrote:
 2. User interface comes last, which is good in general but makes it a
 royal pain to pass notifications back to the UI. In Java I would
 simply have e.g. units.clj call a simple notification function in
 interface.clj, in Clojure I can't do that because I can't mutually
 require the namespaces so I end up either passing a callback
 function or polling some atom, neither of which are particularly
 elegant.

It's often helpful to have one component that acts as a message bus
between the other components.

A quick and dirty example:

;;; --

;;; The message bus
(ns game.event)

;; A map storing the functions that should be called when an event
;; occurs
(def callbacks (atom {}))

;; Functions for subscribing to, and dispatching events
(defn call-when [event callback]
  ...)

(defn dispatch [event  args]
  ...)

;;; --

;;; User interface
(ns game.ui
  (:require [game.event :as event]))

;; An example of an event listener
(event/when :unit-destroyed
(fn [unit]
  (comment Update the UI here)))

;; An example of an event dispatcher. Sends an event to be handled by
;; the component whose responsibility it is. Note that at this point
;; we don't know which component that is.
(defn request-reinforcements-button-clicked []
  (let [amount (.getValue reinforcements-amount-input-field)]
(event/dispatch :reinforcements-requested amount)))

;;; --

I've found this approach to work quite well in game development. As
the components don't care about who reacts to the messages they send,
or who sent the messages they are interested in, it's very easy to
plug in and remove components as needed. For example, you can add a
sound component that plays appropriate sounds when events occur in the
game without requiring any changes to any other components.

This approach is especially helpful when unit testing. You can create
a new bus and plug in just the component under test, and then simulate
all the other components by sending the same messages as they do.

--
Timo

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


Self-referencing map literals

2009-08-31 Thread Timo Mihaljov

When defining a map literal, is it possible to reference the map that is 
being defined?

I have some code that looks like this:

(let [radius 20
  diameter (* 2 radius)
  circumference (* pi diameter)]
  {:radius radius
   :diameter diameter
   :circumference circumference})

I would like to simplify it to something like:

{:radius 20
 :diameter (* 2 (% :radius))
 :circumference (* pi (% :diameter))}

where % is the map itself.

Is this possible with the {}-syntax, or is there a macro to do this in 
the standard library or contrib?

--
Timo

--~--~-~--~~~---~--~~
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: Self-referencing map literals

2009-08-31 Thread Timo Mihaljov

On Mon, Aug 31, 2009 at 09:14:38AM -0400, Chas Emerick wrote:
  You could define your own let-like construct for this:
 
 
  (defmacro letmap [[m kvs  mkvs]  body]
(if m
  `(let [~m {}
 ~@(mapcat (fn [[k v]] `(~m (assoc ~m ~k ~v))) kvs)]
(letmap ~mkvs ~...@body))
  `(do ~...@body)))
 
 
  Usage:
 
  (letmap [a-map   {:a 12
:b (* 2 (:a a-map))}
   another-map {:c (:a a-map)
:d (+ (:b a-map) (:c another-map))}]
[a-map, another-map])
 
  - [{:b 24, :a 12} {:d 36, :c 12}]
 
 Yeah, I needed something like this a while ago, and came up with this:
 
 (defmacro let-map
Equivalent of (let [a 5 b (+ a 5)] {:a a :b b}).
[kvs]
(let [keys (keys (apply hash-map kvs))
  keyword-symbols (mapcat #(vector (keyword (str %)) %) keys)]
`(let [...@kvs]
   (hash-map ~...@keyword-symbols
 
 user= (let-map [a 5 b (inc a) c [a b] d {:foo c :bar (* a b)}])
 {:a 5, :c [5 6], :b 6, :d {:foo [5 6], :bar 30}}
 
 The nice thing about it is that you no longer need to use all the  
 keywords -- the definition of the map's slots becomes far more like  
 defining sequential bindings in a let.

Thank you all for the answers!

I especially like Chas's solution. It didn't occur to me that the 
redundancy can be eliminated by removing the map and leaving in the let 
-- that's brilliant! :-) It's much easier to read because one doesn't 
have to dig into the map to get to the variables, and it looks exactly 
like the common idiom of interdependent let-bindings.

--
Timo

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



clojure.contrib.test-is/run-tests throws NullPointerException w/ invalid args

2009-05-05 Thread Timo Mihaljov

When clojure.contrib.test-is/run-tests is given an invalid argument, it 
throws a NullPointerException:

user= (use 'clojure.contrib.test-is)
nil
user= (run-tests 'asdf)
java.lang.RuntimeException: java.lang.NullPointerException 
(NO_SOURCE_FILE:0)

The issue seems harmless in a simple case like this, but in a more 
complex case the error is quite hard to debug for two reasons:
- When the stack trace is longer it's not immediately obvious what 
caused the NullPointerException.
- The error can be caused by a simple typo so it's quite easy to miss 
when reading the code because the code reads aloud correctly.

Having something like 'clojure.contrib.test-is.NamespaceException: No 
such namespace asdf' would make the source of the error easy to find.

I found this bug by having a namespace called errorr (deliberate 
typo), and accidentally spelled it correctly as error in the argument 
to run-tests. You might say that I got what I deserved for picking a 
clever Web2.0 name like that (and I would agree :), but keep in mind 
that any other typo would have worked and could have been as hard to find.

As an example, here's the the stack trace that one typo gave me.

Exception in thread main java.lang.RuntimeException: 
java.lang.NullPointerException (run-tests.clj:0)
at clojure.lang.Compiler.eval(Compiler.java:4543)
at clojure.lang.Compiler.load(Compiler.java:4857)
at clojure.lang.Compiler.loadFile(Compiler.java:4824)
at clojure.main$load_script__5833.invoke(main.clj:206)
at clojure.main$script_opt__5864.invoke(main.clj:258)
at clojure.main$main__5888.doInvoke(main.clj:333)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at clojure.lang.Var.invoke(Var.java:346)
at clojure.lang.AFn.applyToHelper(AFn.java:173)
at clojure.lang.Var.applyTo(Var.java:463)
at clojure.main.main(main.java:39)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at clojure.lang.LazySeq.seq(LazySeq.java:46)
at clojure.lang.RT.seq(RT.java:436)
at clojure.core$seq__3133.invoke(core.clj:103)
at clojure.core$spread__3240.invoke(core.clj:383)
at clojure.core$spread__3240.invoke(core.clj:384)
at clojure.core$apply__3243.doInvoke(core.clj:390)
at clojure.lang.RestFn.invoke(RestFn.java:443)
at clojure.contrib.test_is$run_tests__4789.doInvoke(test_is.clj:914)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at errorr.engine.gfx.tests$run__7.invoke(tests.clj:5)
at user$eval__10.invoke(run-tests.clj:2)
at clojure.lang.Compiler.eval(Compiler.java:4532)
... 10 more
Caused by: java.lang.NullPointerException
at 
java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:768)
at clojure.lang.Namespace.find(Namespace.java:129)
at clojure.core$find_ns__4309.invoke(core.clj:2347)
at clojure.core$the_ns__4321.invoke(core.clj:2371)
at clojure.core$ns_name__4325.invoke(core.clj:2376)
at clojure.contrib.test_is$fn__4660.invoke(test_is.clj:586)
at clojure.lang.MultiFn.invoke(MultiFn.java:157)
at clojure.contrib.test_is$test_ns__4785.invoke(test_is.clj:896)
at clojure.core$map__3815$fn__3817.invoke(core.clj:1503)
at clojure.lang.LazySeq.seq(LazySeq.java:41)
... 21 more

--
Timo

--~--~-~--~~~---~--~~
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
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: Modifying data structures without changing their interface

2009-04-20 Thread Timo Mihaljov

Timo Mihaljov wrote:
 I'm wondering about how to change a data structure without breaking the
 API used to access it. For example, let's assume that I have a library
 for dealing with records of people and I'm storing them in structs.
 
 (defstruct person :name)
 
 The users of my library access the data stored in the records like any
 other map.
 
 (:name some-person)
 
 When the library's been in use for a while, I realize that I need to
 make a change to the data structure.
 
 (defstruct :first-name :last-name)
 
 The problem is that making this change would break all the clients using
 the library.

After a bit of googling I found what seems to be the perfect solution:
http://kotka.de/projects/clojure/lazy-map.html

(defn new-person [first-name last-name]
   (lazy-struct-map person
:first-name first-name :last-name last-name
:name (str first-name   last-name)))

This is great news! It means I can develop in Clojure like I did in 
Python: start out with direct member access and transparently introduce 
accessors when needed. Yay! :)

Now I only wish that de.kotka.lazymap would become a part of Clojure core.

--
Timo

--~--~-~--~~~---~--~~
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
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: Modifying data structures without changing their interface

2009-04-20 Thread Timo Mihaljov

Laurent PETIT wrote:
 While interesting, this approach seems to me limited to simple cases :
  * limited in possibilities: you are not able to directly use values of 
 other fields. So in more complex cases, you won't be able to combine 
 calculated values without code repetition or prepraration via lets ..
  * limited in extensibility: in a live system, you won't be able to 
 change the function that displays a name because it's hard-coded once 
 and for all at the same time the data is entered in the system. 
 Depending on your use cases, it may or may not be a problem, though.
  * limited for persistence: when you want to persist a lazy-struct-map, 
 the computed value is fixed and stored, where it should not be used I think.
  * limited for equality tests (in relation with limited in 
 extensibility): you will not be able to succesfully compare for 
 equality 2 persons with the exact same essential data, if the way to 
 represent names has been even slightly enhanced, since the :name value 
 will always be used for the comparison as well. So it's not just a 
 problem for performance (very minor in that case, though it may not be 
 that minor in other cases), but also a problem of correctness, in the 
 long run (for systems you want to keep live, and without having to do 
 weird things when you have to marshall / unmarshall your data).

Thanks for your insightful reply, Laurent. You are right, lazyseq is
indeed too limited to be used in the way I proposed. It's still very
cool, though, and I'm sure I'll find some other use for it :)

 I would like to offer another possibility. Not ideal, maybe, but that 
 may answer your needs.
 Basically, the idea is that with a language like clojure that has higher 
 order functions and macros, writing boiler plate code should be a code 
 smell. The good news being that in Java, this boiler plate code smell 
 has no solution in some cases (think about design patterns), while with 
 a lisp, you can do something for that.
 
 By using a macro, you could generate boiler plate getters for your 
 structure. And just override with new definitions those getter/setters 
 that need computations.

The thing that bothers me is that AFAIK there's no standard macro to do
this in Clojure. Combined with the facts that spelling out each accessor
by hand would be a code smell, and all APIs -- internal or external --
need some form of information hiding to remain stable, I'm left feeling
that information hiding should be done in some other way in Clojure.
That's why I asked for the idiomatic way to solve the problem in my
example. One can write FORTRAN in any language, and I could write any
language in Clojure, but I'd rather learn Clojure :)

Another issue I have with the accessor function approach is that it can
be circumvented very easily by accident because the data structure is
exposed to the users of the API. All it takes is typing (:first-name
some-person) instead of (first-name some-person), and you get a map
lookup instead of a call to a getter. Both forms work as long as the
records are maps containing the key :first-name, but the former breaks
when the data structure changes. This is especially problematic when
wrapping an existing map with accessors -- how can you be sure that you
converted each and every key lookup to a getter call?

The standard OO approach to information hiding would be private fields
and accessor methods. Any suggestions for the One True Clojure Pattern
that addresses the same problem?

Now that I've read Programming Clojure I know the capabilities of the
language. My problem is that I have no idea how to apply them to solve
real-world problems, such as the contrived example in my first message.
I hope Mr. Halloway starts writing the sequel soon :)

--
Timo

--~--~-~--~~~---~--~~
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
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: Modifying data structures without changing their interface

2009-04-20 Thread Timo Mihaljov

Laurent PETIT wrote:
 What do others think about these 2 above statements ?
 
 The standard OO approach to information hiding would be private fields
 and accessor methods. Any suggestions for the One True Clojure Pattern
 that addresses the same problem?
 
 
 I think accessor methods.

Based on our discussion so far, I would use the following approach. In
the spirit of defn-, I appended a dash after field names that should be
accessed via accessor functions. This is similar to the Python idiom of
prefixing private members with an underscore to prevent _accidental_
direct modification. The symbols are also used as the initial versions
of the getter functions. This way there's so little code that no macros
are needed.

 ;;; Initial version

 ;; Library
 (defstruct person :full-name-)

 (defn new-person [full-name]
   (struct person full-name))

 (def full-name :full-name-)

 ;; Client
 (def p (new-person James Bond))
 (println (full-name p))


 ;;; Modified version

 ;; Library
 (defstruct person :first-name- :last-name-)

 (defn new-person [full-name]
   (let [[first-name last-name] (.split full-name  )]
 (struct person first-name last-name)))

 (def first-name :first-name-)
 (def last-name :last-name-)

 (defn full-name [the-person]
   (str (first-name the-person)   (last-name the-person)))

 ;; Client
 (def p (new-person James Bond))
 (println (last-name p))
 (println (full-name p))

How does this code look like to a experienced Clojure programmer? Does
it seem to be in the spirit of the language?

--
Timo

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



Modifying data structures without changing their interface

2009-04-19 Thread Timo Mihaljov

Hi,


I'm wondering about how to change a data structure without breaking the
API used to access it. For example, let's assume that I have a library
for dealing with records of people and I'm storing them in structs.

 (defstruct person :name)

The users of my library access the data stored in the records like any
other map.

 (:name some-person)

When the library's been in use for a while, I realize that I need to
make a change to the data structure.

 (defstruct :first-name :last-name)

The problem is that making this change would break all the clients using
the library.

The obvious and traditional solution, at least for someone used to
thinking in OO terms, would be to tell the clients of the library to
treat the records as opaque handles, and only use the library's accessor
functions to access their contents. However, I don't like this approach
because it leads to a lot of boilerplate code that's there just in case
I'll need it some day. It also prevents my clients from using generic
map manipulation functions on the records.

In Python, my current go-to language, I can have my cake and eat it too
by using class properties.

 # A struct-like class whose members can be manipulated directly
 class Person1(object):
 name = full name

 p1 = Person1()
 print p1.name


 # Like above, but with three members, one of which is calculated by
 # a function when it is accessed
 class Person2(object):
 first_name = first
 last_name = last

 def get_name(self):
 return self.first_name +   + self.last_name
 name = property(get_name)

 p2 = Person2()
 print p2.name   # The old API still works, even though the data is
 # stored in a different way


What's the idiomatic Clojure way of dealing with this issue?


--
Timo

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



System.loadLibrary() does not work

2009-03-29 Thread Timo Mihaljov

I'm trying to use Clojure to call a library via JNI. Here's a working
piece of Java code that I'm trying to convert to Clojure:

import libfoo.Foo;  // A GlueGen-generated wrapper

class Test {
static {
System.loadLibrary(foo);  // The original library
System.loadLibrary(foojni);   // A GlueGen-generated wrapper
}

public static void main(String[] args) {
Foo.do_nothing();
}
}

Here's my Clojure conversion:

(import '(libfoo Foo))

(System/loadLibrary foo)
(System/loadLibrary foojni)

(Foo/do_nothing)

Running this Clojure program results in:

java.lang.UnsatisfiedLinkError: libfoo.Foo.do_nothing()V
(test.clj:0)

as if the library wasn't dynamically linked at all.

The Clojure code works if I copy the static block from my Java client
code into the GlueGen generated Java class, and remove the
System/loadLibrary calls from the Clojure client.

If the libraries are loaded in the static block of the Java wrapper
class, calling System/loadLibrary in Clojure results in:

java.lang.UnsatisfiedLinkError: Native Library snip/libfoo.so
already loaded in another classloader (test.clj:0)

Is there a working equivalent of System.loadLibrary() in the Clojure
API? I tried to google for it, but couldn't find anything.

Thanks,
--
Timo

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