11

How can I create a lazy sequence of random numbers?

My current code:

(import '(java.util Random))

(def r (new Random))
(defn rnd [_] 
    (.nextInt r 10))

(defn random-numbers [max] 
    (iterate #(.nextInt r max) (.nextInt r max)))

(println (take 5 (random-numbers 10)))

executing it throws an exception:

(Exception in thread "main" clojure.lang.ArityException: Wrong number of args (1) passed to: user$random-numbers$fn at clojure.lang.AFn.throwArity(AFn.java:437) at clojure.lang.AFn.invoke(AFn.java:39) at clojure.core$iterate$fn__3870.invoke(core.clj:2596) at clojure.lang.LazySeq.sval(LazySeq.java:42) at clojure.lang.LazySeq.seq(LazySeq.java:60) at clojure.lang.RT.seq(RT.java:466) at clojure.core$seq.invoke(core.clj:133) at clojure.core$take$fn__3836.invoke(core.clj:2499) at clojure.lang.LazySeq.sval(LazySeq.java:42) at clojure.lang.LazySeq.seq(LazySeq.java:60) at clojure.lang.Cons.next(Cons.java:39) at clojure.lang.RT.next(RT.java:580) at clojure.core$next.invoke(core.clj:64) at clojure.core$nthnext.invoke(core.clj:2752) at clojure.core$print_sequential.invoke(core_print.clj:57) at clojure.core$fn__4990.invoke(core_print.clj:140) at clojure.lang.MultiFn.invoke(MultiFn.java:167) at clojure.core$pr_on.invoke(core.clj:3264) at clojure.core$pr.invoke(core.clj:3276) at clojure.lang.AFn.applyToHelper(AFn.java:161) at clojure.lang.RestFn.applyTo(RestFn.java:132) at clojure.core$apply.invoke(core.clj:600) at clojure.core$prn.doInvoke(core.clj:3309) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:600) at clojure.core$println.doInvoke(core.clj:3329) at clojure.lang.RestFn.invoke(RestFn.java:408) at user$eval7.invoke(testing.clj:12) at clojure.lang.Compiler.eval(Compiler.java:6465) at clojure.lang.Compiler.load(Compiler.java:6902) at clojure.lang.Compiler.loadFile(Compiler.java:6863) at clojure.main$load_script.invoke(main.clj:282) at clojure.main$script_opt.invoke(main.clj:342) at clojure.main$main.doInvoke(main.clj:426) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.lang.Var.invoke(Var.java:401) at clojure.lang.AFn.applyToHelper(AFn.java:161) at clojure.lang.Var.applyTo(Var.java:518) at clojure.main.main(main.java:37) [Finished in 3.8s with exit code 1]

Is this a completey wrong approach, because I am using state, namely r is an instance of java.util.Random, or is it just a nooby syntax error?

I just studing clojure on myself, so please bear with me :) .

1
  • Thanks for including the whole stacktrace. Here it's not really necessary, but it can help immensely and often people don't bother. Commented Jul 31, 2012 at 18:36

4 Answers 4

31

repeatedly is great for repeatedly running a function and gathering the results in a seq

user> (take 10 (repeatedly #(rand-int 42)))
(14 0 38 14 37 6 37 32 38 22)

as for your original approach: iterate takes an argument, feeds it to a function and then takes the result of that and passes it back to the same function. I't not quite what you want here because the function you are using doesn't need any arguments. You can of course give it a placeholder for that argument and get it working, though repeatedly is likely a better fit.

(defn random-numbers [max]
  (iterate (fn [ignored-arg] (.nextInt r max)) (.nextInt r max)))
#'user/random-numbers

user> (println (take 5 (random-numbers 10)))
(3 0 0 2 0)
Sign up to request clarification or add additional context in comments.

Comments

7

As a general guide, do not start with a class/function from Java. Look first at Clojure's core functions and namespaces in clojure.* (and then at the contributed namespaces which are now in modular repos: see http://dev.clojure.org/display/doc/Clojure+Contrib); rand-int itself is readily available in clojure-core. So, how would one start the search for a random number helper?

With Clojure 1.3 onwards, you can "use" the clojure-repl namespace to have access to the handy apropos function (used in the same spirit as the apropos command in Unix/linux); apropos returns all matching defs in namespaces loaded so far.

user> (use 'clojure.repl)
nil
user> (apropos "rand")
(rand rand-int rand-nth)

The find-doc function in clojure.repl is also another alternative.

The other pointer is to search at www.clojuredocs.org which includes usage-examples for the funcs in clojure core and clojure.*.

Comments

0

For testing purposes at least, it's good to be able to repeat a "random" sequence by seeding the generator. The new spec library reports the results of its tests this way.

The native Clojure functions don't let you seed a random sequence, so we have to resort to the underlying Java functions:

(defn random-int-seq
  "Generates a reproducible sequence of 'random' integers (actually longs)
  from an integer (long) seed. Supplies its own random seed if need be."
  ([] (random-int-seq (rand-int Integer/MAX_VALUE)))
  ([seed]
   (let [gen (java.util.Random. seed)]
     (repeatedly #(.nextLong gen))))) 

Comments

0

Lets use a transducer shall we?

 (def xf (map (fn [x] (* 10 (rand)))))

We can also use rand-int as:

(def xf (map (fn [x] (* 10 (rand-int 10)))))

To use this to generate lazy sequence, we'll use sequence

(sequence xf (range))

This returns a lazy sequence of random numbers. To get a complete sequence of n numbers we can use take as:

(take n (sequence xf (range)))

3 Comments

Hi! Could you please explain the role of variable [x] in your two xf definitions? To me, they seem to have no effect, and xf could have no argument (i.e. (def xf [] ...), but I'm new to Clojure and may have missed something worth learning :-)
The function you pass in a map needs an argument, so that it can map over it. It it makes any easier, read it as fn [_] in place of fn[x]
OK, said otherwise, we pass the output of (range) to our custom function, that does nothing out of the generated value but returns a random value instead; that's smart. Thanks for the clarification!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.