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

Haskell и случайные числа

Я несколько дней возился с Haskell и наткнулся на проблему.

Мне нужен метод, который возвращает случайный список целых чисел (Rand [[Int]]).

Итак, я определил тип: type Rand a = StdGen -> (a, StdGen). Я смог каким-то образом создать Rand IO Integer и Rand [IO Integer] ((returnR lst) :: StdGen -> ([IO Integer], StdGen)). Любые советы по созданию Rand [[Int]]?

4b9b3361

Ответ 1

Как избежать IO зависит от того, почему его вводят в первую очередь. В то время как генераторы псевдослучайных чисел по своей природе ориентированы на состояние, нет никакой причины IO.

Я собираюсь угадать и сказать, что вы используете newStdGen или getStdGen, чтобы получить свой первоначальный PRNG. Если это так, то нет возможности полностью избежать IO. Вы можете вместо этого перенести PRNG на mkStdGen, имея в виду, что одно и то же семя приведет к той же "случайной" последовательности чисел.

Скорее всего, что вы хотите сделать, это получить PRNG внутри IO, а затем передать это как аргумент чистой функции. Разумеется, в конце все дело будет завернуто в IO, но промежуточные вычисления ему не понадобятся. Вот краткий пример, чтобы дать вам идею:

import System.Random

type Rand a = StdGen -> (a, StdGen)

getPRNG = do
    rng <- newStdGen
    let x = usePRNG rng
    print x

usePRNG :: StdGen -> [[Int]]
usePRNG rng = let (x, rng') = randomInts 5 rng
                  (y, _) = randomInts 10 rng'
              in [x, y]

randomInts :: Int -> Rand [Int]
randomInts 0 rng = ([], rng)
randomInts n rng = let (x, rng') = next rng
                       (xs, rng'') = randomInts (n - 1) rng'
                   in (x:xs, rng'')

Вы могли заметить, что код с использованием PRNG становится довольно уродливым из-за постоянного пропускания текущего значения взад и вперед. Это также потенциально подвержено ошибкам, поскольку было бы легко случайно повторно использовать старое значение. Как упоминалось выше, использование того же значения PRNG даст ту же последовательность чисел, которая обычно не та, что вы хотите. Обе проблемы - прекрасный пример того, где имеет смысл использовать монаду State, которая выходит из темы здесь, но вы можете захотеть взглянуть на нее дальше.

Ответ 2

Вы воссоздаете MonadRandom в Hackage. Если это больше, чем просто эксперимент, чтобы увидеть, можете ли вы это сделать, вы можете использовать эту библиотеку вместо этого.

Ответ 3

Если вы хотите получить бесконечный список Integer, вы столкнетесь с проблемами, поскольку вы никогда не получите значение StdGen. То, что вы хотите сделать здесь, - это split the StdGen, сначала перейдите еще раз и "используйте" другую половину, чтобы создать бесконечный список целых чисел. Что-то вроде этого:

infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
    (g1,g2) = split g
    ints = randoms g1

Однако, если вы затем повторите этот подход, чтобы получить бесконечную матрицу Integer (которую вы, похоже, хотите, используя Rand [[Int]]), вы можете столкнуться с проблемами статистического характера: я не знаю, как хорошо StdGen имеет дело с повторением split ting. Возможно, другая реализация RandomGen может быть лучше, или вы можете попытаться использовать какую-то диагональную прогулку, чтобы превратить [Int] в [[Int]].

Ответ 4

Используя монадическую нотацию, вы должны написать что-то вроде

randomList gen = do
    randomLength <- yourRandomInteger
    loop gen (randomLength + 1)
 where
    loop gen 1 = gen
    loop gen n = do { x <- gen; xs <- loop gen (n - 1); return (x:xs) }

И с этим

randomInts :: Rand [Int]
randomInts = randomList yourRandomInteger

randomLists :: Rand [[Int]]
randomLists = randomList randomInts

Что касается самих монадических вычислений, посмотрите в этой статье. Обратите внимание, что случайные генераторы чисты, вам не нужно использовать IO только для этой цели.