Подтвердить что ты не робот

Почему многократно не воспроизводят воспроизводимые случайные числа при использовании семени в Clojure?

У меня есть некоторые функции, для которых требуется серия случайных чисел, поэтому я взял несколько простых примитивов, таких как #(inc (g/uniform 0 n)), и я не могу создать воспроизводимую серию случайных чисел, хотя я перезаписываю *rnd*, если я не сгенерировал их, как показано ниже. Я не могу себе представить, что лучший способ, так может кто-нибудь указать, как сделать это лучше?

Примечание. Я запускаю каждый пример ниже трех раз, как показано для получения заданных результатов.

(ns example.show
  (:require [clojure.data.generators :as g]))


(binding [g/*rnd* (java.util.Random. 42)]
  (take 10 (repeatedly #(inc (g/uniform 0 n))))

=> (9 4 5 4 4 5 1 8 2 9)

=> (2 1 1 6 3 10 10 4 1 9)

=> (10 4 7 8 9 6 10 1 8 3)


(binding [g/*rnd* (java.util.Random. 42)]
  (g/reps 10 #(inc (g/uniform 0 n)))

=> (3 9 4 6 3 8 6 6 5 4)

=> (7 8 4 7 7 5 7 4 8 7)

=> (2 8 7 8 8 8 9 2 6 5)

;; This seems to work
(binding [g/*rnd* (java.util.Random. 42)]
  (letfn [(roll [n] #(inc (g/uniform 0 n)))]
    [((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10))]))

=> [8 7 4 3 7 10 4 3 5 8]

=> [8 7 4 3 7 10 4 3 5 8]

=> [8 7 4 3 7 10 4 3 5 8]
4b9b3361

Ответ 1

Из-за лени. Вы возвращаетесь с binding до того, как будет реализована последовательность. Поэтому ленивая последовательность никогда не видит привязки, которые вы устанавливаете. Одним из решений было бы принудительное выполнение с doall в последовательности внутри привязки.

Ответ 2

Если, как указывает ваш комментарий к другому ответу, вы хотите сохранить лень, тогда вам нужно применить привязку к функции, переданной в repeatedly, захватив семя, созданную за пределами ленивого seq. Например:

(defn rand-seq [seed]
  (let [r (java.util.Random. seed)]
    (repeatedly #(binding [g/*rnd* r]
                   (inc (g/uniform 0 10))))))

(take 10 (rand-seq 42))
#=> (8 7 4 3 7 10 4 3 5 8)

(take 10 (rand-seq 42))
#=> (8 7 4 3 7 10 4 3 5 8)