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