Как создать ленивую последовательность случайных чисел в clojure

Как создать ленивую последовательность случайных чисел?

Мой текущий код:

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

выполнение этого запроса вызывает исключение:

(Исключение в потоке "main" clojure.lang.ArityException: неправильное количество аргументов (1), переданных в: user $random-numbers $fn     в clojure.lang.AFn.throwArity(AFn.java:437)     at clojure.lang.AFn.invoke(AFn.java:39)     at clojure.core $итерация $fn_3870.invoke(core.clj: 2596)     в clojure.lang.LazySeq.sval(LazySeq.java:42)     в clojure.lang.LazySeq.seq(LazySeq.java:60)     в 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)     в clojure.lang.LazySeq.sval(LazySeq.java:42)     в clojure.lang.LazySeq.seq(LazySeq.java:60)     в clojure.lang.Cons.next(Cons.java:39)     в clojure.lang.RT.next(RT.java:580)     at clojure.core $next.invoke(core.clj: 64)     в clojure.core $nthnext.invoke(core.clj: 2752)     at clojure.core $print_sequential.invoke(core_print.clj: 57)     в clojure.core $fn__4990.invoke(core_print.clj: 140)     в clojure.lang.MultiFn.invoke(MultiFn.java:167)     на clojure.core $pr_on.invoke(core.clj: 3264)     at clojure.core $pr.invoke(core.clj: 3276)     в clojure.lang.AFn.applyToHelper(AFn.java:161)     в clojure.lang.RestFn.applyTo(RestFn.java:132)     в clojure.core $apply.invoke(core.clj: 600)     в clojure.core $prn.doInvoke(core.clj: 3309)     в clojure.lang.RestFn.applyTo(RestFn.java:137)     в clojure.core $apply.invoke(core.clj: 600)     at clojure.core $println.doInvoke(core.clj: 3329)     в clojure.lang.RestFn.invoke(RestFn.java:408)     у пользователя $eval7.invoke(testing.clj: 12)     в clojure.lang.Compiler.eval(Compiler.java:6465)     в clojure.lang.Compiler.load(Compiler.java:6902)     в 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)     в clojure.lang.RestFn.invoke(RestFn.java:408)     в clojure.lang.Var.invoke(Var.java:401)     в clojure.lang.AFn.applyToHelper(AFn.java:161)     в clojure.lang.Var.applyTo(Var.java:518)     в clojure..main.main(main.java:37) [Закончено в 3.8 с кодом выхода 1]

Является ли это совершенно неправильным подходом, потому что я использую состояние, а именно r является экземпляром java.util.Random или это просто ошибка синтаксиса nooby?

Я просто изучал clojure на себе, поэтому, пожалуйста, со мной обойдется:).

Ответ 1

repeatedly отлично подходит для многократного запуска функции и сбора результатов в seq

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

как для вашего первоначального подхода: итерация принимает аргумент, передает его функции, а затем берет результат этого и возвращает его к той же функции. Я не совсем то, что вы хотите здесь, потому что функция, которую вы используете, не нуждается в каких-либо аргументах. Разумеется, вы можете сделать это заполнитель для этого аргумента и заставить его работать, хотя repeatedly, скорее всего, лучше подходит.

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

Ответ 2

Как общее руководство, не начинайте с класса/функции из Java. Посмотрите сначала на основные функции и пространства имен Clojure в clojure. * (А затем на предоставленные пространства имен, которые теперь находятся в модульных репозиториях: см. http://dev.clojure.org/display/doc/Clojure+Contrib); Сам rand-int легко доступен в clojure -коре. Итак, как бы начать поиск помощника случайных чисел?

С Clojure 1.3, вы можете "использовать" пространство имен clojure -repl для доступа к удобной функции apropos (используемой в том же духе, что и команда apropos в Unix/linux); apopos возвращает все соответствующие defs в пространствах имен, загруженных до сих пор.

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

Функция find-doc в clojure.repl также является другой альтернативой.

Другим указателем является поиск по адресу www.clojuredocs.org, который включает примеры использования для funcs в ядре Clojure и clojure. *.

Ответ 3

Для целей тестирования, по крайней мере, хорошо иметь возможность повторять "случайную" последовательность путем посева генератора. Новая библиотека spec сообщает результаты своих тестов таким образом.

Нативные функции Clojure не позволяют вам посеять случайную последовательность, поэтому нам приходится прибегать к базовым функциям Java:

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

Ответ 4

Используется ли датчик?

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

Мы также можем использовать rand-int как:

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

Чтобы использовать это для создания ленивой последовательности, мы будем использовать sequence

(sequence xf (range))

Это возвращает ленивую последовательность случайных чисел. Чтобы получить полную последовательность n чисел, мы можем использовать take как:

(take n (sequence xf (range)))