FWIW dynvars are quite a common solution to these kind of scenarios:
e.g. In my own library I've defined a default Random instance which is
used by all related library fns, e.g.:

(def ^:dynamic ^java.util.Random *rnd* (java.util.Random. 23))

(defn random
  ([x] (* x (.nextDouble *rnd*)))
  ([x y] (+ x (* (- y x) (.nextDouble *rnd*)))))

If client code want to use a different Random implementation than the
default, it only needs to wrap calls to these fns with a new temporary
binding:

(binding [*rnd* org.uncommons.maths.random.MersenneTwisterRNG] (random 100))

or via:

(defmacro with-random [r & body] `(binding [*rnd* ~r] (do ~@body)))

and then:

(with-random (org.uncommons.maths.random.MersenneTwisterRNG.) (random 100))

K.

On 5 December 2012 20:45, Steve Miner <stevemi...@gmail.com> wrote:
> You should treat rand and friends like i/o.  Don't bury them deep in your 
> code.  Write your pure functions so that they take a seed value (or 
> sequence).  Generate the random values from outside of the important 
> functions,  maybe providing a convenience wrapper function around your main 
> logic.
>
> (defn foo-pure [val seed] ...)
>
> (defn foo-uses-rand [val] (foo-pure val (rand)))
>
>
> On Dec 5, 2012, at 1:48 PM, JonC <jonathan.co...@gmail.com> wrote:
>
>> Ok: first of all, Clojure has outstandingly the best core library I've seen. 
>> I am awed by how wonderfully the protocol approach makes data structures, 
>> and the good taste applied to getting an API that's reasonably minimal and 
>> wonderfully complete. I've not posted before because I've had nothing to ask 
>> - everything is super-clear, especially now I have a copy of JoC. But I 
>> would suggest that there is one easily corrected area where things are 
>> imperfect: -
>>
>> One of the big advantages of functional coding to me is rock solid 
>> testability - same inputs, same outputs; easy to test, easy to debug.
>>
>> Obviously psuedo-random  numbers and io present problems with this. Now, the 
>> normal way for an API to discourage something problematic is to make it 
>> difficult, and to encourage correct behavoiur by making it easy. So list's 
>> lack of nth but possession of first, second rest and last shout out "Do NOT 
>> use for random access!" while vector's api says "Use me instead!"
>>
>> Now we come to rand, rand-int, rand-nth. They're the easiest things to use 
>> for their purpose, so they shout "Use me!" But.. they break the 
>> repeatability paradigm. Because they use Java's default random number 
>> generator instance, which has a private and unsettable seed, you can't get 
>> repeatabilty. In Java, this isn't actually too awful because you can 
>> instantiate an rng of your own and use it in just the same way - but if you 
>> do this in clojure, bang goes your rand-nth. Yes, the problem is one you can 
>> easily solve with a few minutes coding. But an api should gently lure into 
>> doing things the right way rather than wrong one - so wouldn't it be a good 
>> idea to add change the standard api to include a function that takes a seed? 
>> A random that allows you to see the last "seed" would be even better. That 
>> way when you get
>>
>> => (foo-uses-rand "bar')
>> ..crazy result *sometimes*
>>
>> then
>>
>> => (def wrong (get-last-rand-seed))
>>
>> would give you the seed needed to repeat the last call to any random fn. So 
>> you could fix your code and verify by re-seeding with "wrong" and repeating 
>> the function call.
>>
>> To me this seems a nice low-impact solution. It wouldn't make repeatability 
>> bullet proof, but I'd suggest it would be an easily implemented mild 
>> improvement for a future version of clojure.
>>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

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

Reply via email to