2012-07-30 21 views
10

¿Cómo puedo crear una secuencia diferida de números aleatorios?Cómo crear una secuencia perezosa de números aleatorios en clojure

Mi código actual:

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

ejecución lanza una excepción:

(Excepción en hilo clojure.lang.ArityException "principal": Número incorrecto de argumentos (1) pasan a: usuario $ random-numbers $ fn en clojure.lang.AFn.throwArity (AFn.java:437) en clojure.lang.AFn.invoke (AFn.java:39) en clojure.core $ iterate $ fn_ 3870 .invoke (core.clj: 2596) en clojure.lang. LazySeq.sval (LazySeq.java:42) en clojure.lang.LazySeq.seq (LazySeq.java:60) en clojure.lang.RT.seq (RT.java:466) en clojure.core $ seq. invoke (core.clj: 133) en clojure.core $ take $ fn _3836.invoke (core.clj: 2499) en clojure.lang.LazySeq.sval (LazySeq.java:42) en clojure.lang. LazySeq.seq (LazySeq.java:60) en clojure.lang.Cons.next (Cons.java:39) en clojure.lang.RT.next (RT.java:580) en clojure.core $ next. invoke (core.clj: 64) en clojure.core $ nthnext.invoke (core.clj: 2752) en clojure.core $ print_sequential.invoke (core_print.clj: 57) en clojure.core $ fn__4990.invoke (core_print.clj: 140) en clojure.lang.MultiFn.invoke (MultiFn.java:167) en clojure.core $ pr_on.invoke (core.clj: 3264) en clojure.core $ pr.invoke (core.clj: 3276) en clojure.lang.AFn.applyToHelper (AFn.java:161) en clojure.lang.RestFn.applyTo (RestFn.java:132) en clojure.core $ apply.invoke (core.clj: 600) en clojure. core $ prn.doInvoke (core.clj: 3309) en clojure.lang.RestFn.applyTo (RestFn.java:137) en clojure.core $ apply.invoke (core.clj: 600) en clojure.core $ println.doInvoke (core.clj: 3329) en clojure.lang.RestFn.invoke (RestFn.java:408) en el usuario $ eval7.invoke (testing.clj: 12) en clojure.lang.Compiler.eval (Comp iler.java:6465) en clojure.lang.Compiler.load (Compiler.java:6902) en clojure.lang.Compiler.loadFile (Compiler.java:6863) en clojure.main $ load_script.invoke (main. clj: 282) en clojure.main $ script_opt.invoke (main.clj: 342) en clojure.main $ main.doInvoke (main.clj: 426) en clojure.lang.RestFn.invoke (RestFn.java: 408) en clojure.lang.Var.invoke (Var.java:401) en clojure.lang.AFn.applyToHelper (AFn.java:161) en clojure.lang.Var.applyTo (Var.java:518) en clojure.main.main (main.java:37) [Terminado en 3.8s con código de salida 1]

¿Es este un enfoque completamente erróneo, porque estoy usando el estado, es decir, r es una instancia de java.util.Random, o es simplemente un error de sintaxis nooby?

Acabo de estudiar clojure en mí mismo, así que por favor desnudo conmigo :).

+0

Gracias por incluir toda la StackTrace. Aquí no es realmente necesario, pero puede ayudar inmensamente y, a menudo, la gente no se molesta. – amalloy

Respuesta

28

repeatedly es ideal para correr en varias ocasiones una función y la recopilación de los resultados en un ss

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

como por su enfoque original: Iterar toma un argumento, se alimenta a una función y luego toma el resultado de eso y lo devuelve a la misma función. No es exactamente lo que quieres aquí porque la función que estás utilizando no necesita ningún argumento. Por supuesto, puede darle un marcador de posición para ese argumento y ponerlo en funcionamiento, aunque es probable que repeatedly se ajuste mejor.

(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

Como guía general, no comience con una clase/función de Java. Mire primero las funciones principales y los espacios de nombres de Clojure en clojure. * (Y luego en los espacios de nombres aportados que ahora están en repositorios modulares: vea http://dev.clojure.org/display/doc/Clojure+Contrib); rand-int en sí mismo está disponible en clojure-core. Entonces, ¿cómo comenzaría la búsqueda de un número aleatorio de ayuda?

Con Clojure 1.3 en adelante, puede "usar" el espacio de nombres clojure-repl para tener acceso a la práctica función apropos (utilizada con el mismo espíritu que el comando apropos en Unix/linux); apropos devuelve todas las definiciones coincidentes en los espacios de nombres cargados hasta el momento.

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

La función find-doc en clojure.repl es también otra alternativa.

El otro puntero es buscar en www.clojuredocs.org que incluye ejemplos de uso para los funcs en clojure core y clojure. *.

0

Para fines de prueba al menos, es bueno poder repetir una secuencia "aleatoria" sembrando el generador. La nueva biblioteca spec informa los resultados de sus pruebas de esta manera.

Las funciones nativas de Clojure no deje que se siembra una secuencia aleatoria, por lo que tenemos que recurrir a las funciones de Java subyacentes:

(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

Permite utilizar un transductor de acuerdo?

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

También podemos utilizar como rand-int:

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

Para utilizar esta secuencia para generar perezoso, usaremos sequence

(sequence xf (range)) 

Esto devuelve una secuencia de números aleatorios perezoso. Para obtener una secuencia completa de números de n podemos utilizar take como:

(take n (sequence xf (range))) 
Cuestiones relacionadas