2012-07-30 9 views
10

Wie kann ich eine Lazy-Sequenz von Zufallszahlen erstellen?So erstellen Sie eine Lazy-Sequenz von Zufallszahlen in Clojure

My aktuellen 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))) 

Ausführen es eine Ausnahme auslöst:

(Exception in thread "main" clojure.lang.ArityException: Falsche Anzahl von args (1) zu übergeben: Benutzer $ Zufallszahlen $ fn bei clojure.lang.AFn.throwArity (AFn.java:437) bei clojure.lang.AFn.invoke (AFn.java:39) bei clojure.core $ iterate $ fn_ 3870 .invozieren (core.clj: 2596) bei clojure.lang. LazySeq.sval (LazySeq.java:42) bei clojure.lang.LazySeq.seq (LazySeq.java:60) bei clojure.lang.RT.seq (RT.java:466) bei clojure.core $ seq. (core.clj: 133) aufrufen bei clojure.core nehmen $ $ fn _3836.invoke (core.clj: 2499) bei clojure.lang.LazySeq.sval (LazySeq.java:42) bei clojure.lang. LazySeq.seq (LazySeq.java:60) bei clojure.lang.Cons.next (Cons.java:39) bei clojure.lang.RT.next (RT.java:580) bei clojure.core $ nächste. Rufen Sie an (core.clj: 64) bei clojure.core $ nthnext.invoke (core.clj: 2752) bei clojure.core $ print_sequential.invoke (core_print.clj: 57) bei clojure.core $ fn__4990.invoke (core_print.clj: 140) bei clojure.lang.MultiFn.invoke (MultiFn.java:167) bei clojure.core $ pr_on.invoke (core.clj: 3264) bei clojure.core $ pr.invoke (core.clj: 3276) bei clojure.lang.AFn.applyToHelper (AFn.java:161) bei clojure.lang.RestFn.applyTo (RestFn.java:132) bei clojure.core $ apply.invoke (core.clj: 600) bei clojure. core $ prn.doInvoke (core.clj: 3309) bei clojure.lang.RestFn.applyTo (RestFn.java:137) bei clojure.core $ apply.invoke (core.clj: 600) bei clojure.core $ println.doInvoke (core.clj: 3329) bei clojure.lang.RestFn.invoke (RestFn.java:408) bei Benutzer $ eval7.invoke (testing.clj: 12) bei clojure.lang.Compiler.eval (Komp iter.java:6465) bei clojure.lang.Compiler.load (Compiler.java:6902) bei clojure.lang.Compiler.loadFile (Compiler.java:6863) bei clojure.main $ load_script.invoke (main. clj: 282) bei clojure.main $ script_opt.invoke (main.clj: 342) bei clojure.main $ main.doInvoke (main.clj: 426) bei clojure.lang.RestFn.invoke (RestFn.java: 408) bei clojure.lang.Var.invoke (Var.java:401) bei clojure.lang.AFn.applyToHelper (AFn.java:161) bei clojure.lang.Var.applyTo (Var.java:518) bei clojure.main.main (main.java:37) [Fertig in 3.8s mit Exitcode 1]

Ist dies ein völlig falscher Ansatz, weil ich Zustand verwende, nämlich r ist eine Instanz von java.util.Random, oder ist es nur ein Nooby Syntaxfehler?

Ich studiere nur clojure auf mich, also bitte bare mit mir :).

+0

Vielen Dank für die ganze stacktrace einschließlich. Hier ist es nicht wirklich notwendig, aber es kann immens helfen und oft stören die Leute nicht. – amalloy

Antwort

28

repeatedly ist für immer wieder eine Funktion und das Sammeln der Ergebnisse in einem seq

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

wie für Ihren ursprünglichen Ansatz ausgeführt wird: iterate nimmt ein Argument, führt es zu einer Funktion und nimmt dann das Ergebnis, dass und übergibt es wieder an die gleiche Funktion. Ich will nicht, was Sie hier wollen, weil die von Ihnen verwendete Funktion keine Argumente benötigt. Sie können natürlich einen Platzhalter für dieses Argument geben und es funktioniert, obwohl repeatedly ist wahrscheinlich eine bessere Passform.

(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) 
6

Als allgemeine Richtlinie, beginnen Sie nicht mit einer Klasse/Funktion von Java. Betrachten Sie zuerst Clojures Kernfunktionen und Namespaces in clojure. * (Und dann bei den beigesteuerten Namespaces, die sich jetzt in modularen Repos befinden: siehe http://dev.clojure.org/display/doc/Clojure+Contrib); rand-int selbst ist in clojure-core verfügbar. Also, wie würde man die Suche nach einem Zufallszahlenhelfer starten?

Mit Clojure 1.3 können Sie den clojure-repl-Namespace "verwenden", um Zugriff auf die handliche apropos-Funktion zu erhalten (im gleichen Sinne wie der Befehl apropos in Unix/linux); apropos gibt alle passenden Defs in den bisher geladenen Namespaces zurück.

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

Der Fund-doc-Funktion in clojure.repl ist auch eine weitere Alternative.

Der andere Zeiger ist auf www.clojuredocs.org zu suchen, die Anwendungsbeispiele für die Funktionen in clojure core und clojure enthält. *.

0

Zumindest zu Testzwecken ist es gut, eine "zufällige" Sequenz durch Seeding des Generators wiederholen zu können. Die neue Bibliothek spec meldet die Ergebnisse ihrer Tests auf diese Weise.

der nativen Clojure Funktionen lassen Sie nicht eine zufällige Folge Samen, also müssen wir die zugrunde liegenden Java-Funktionen zurückgreifen:

(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))))) 
0

Lets verwenden ein Wandler sollen wir?

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

Wir können auch verwenden rand-int als:

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

Um dies zu verwenden faul Sequenz zu erzeugen, wir sequence

(sequence xf (range)) 

Dies gibt eine faule Folge von Zufallszahlen verwenden werden. Um eine vollständige Sequenz von n Zahlen zu erhalten können wir verwenden take als:

(take n (sequence xf (range))) 
Verwandte Themen