Я смешивал с Haskell несколько дней и споткнулся в проблему.
Мне нужен метод, который возвращает случайный список целых чисел (Rand [[Интервал]]).
Так, я определил тип: type Rand a = StdGen -> (a, StdGen)
. Я смог произвести Rand IO Integer
и Rand [IO Integer]
( (returnR lst) :: StdGen -> ([IO Integer], StdGen)
) так или иначе. Любые подсказки, как произвести Rand [[Int]]
?
Как избежать ввода-вывода
зависит от того, почему он вообще вводится. Хотя генераторы псевдослучайных чисел по своей сути ориентированы на состояние, нет никаких причин для участия IO
.
Я собираюсь предположить, что вы используете newStdGen
или getStdGen
, чтобы получить начальный ГПСЧ. Если это так, то полностью избежать IO
невозможно. Вместо этого вы можете напрямую заполнить PRNG с помощью mkStdGen
, помня, что одно и то же начальное значение приведет к той же "случайной" числовой последовательности.
Скорее всего, вы хотите получить ГПСЧ внутри 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 даст одинаковую последовательность чисел, что обычно не то, что вам нужно. Обе задачи являются прекрасным примером того, где имеет смысл использовать монаду State
- что здесь не по теме, но вы, возможно, захотите изучить ее позже.
Используя монадическую нотацию, вы должны иметь возможность написать что-то вроде
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
только для этой цели.
Если вы хотите получить бесконечный список Integer
s, вы столкнетесь с проблемами, так как вы никогда не получите значение StdGen
. обратно. Здесь вы хотите разделить
StdGen
сначала, передать одну половину снова и «использовать» другую половину для создания бесконечного списка целых чисел. Примерно так:
infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
(g1,g2) = split g
ints = randoms g1
Однако, если вы затем повторите этот подход, чтобы получить бесконечную матрицу Integer
s (что вам, кажется, нужно, используя Rand [[Int]]
), вы можете столкнуться с проблемами статистического характера: я не знаю, насколько хорошо StdGen
справляется с повторным разбиением
тингом. Может быть, другая реализация RandomGen
могла бы быть лучше, или вы могли бы попытаться использовать какой-то диагональный обход, чтобы превратить [Int]
в [[Int]]
.
Вы воссоздаете MonadRandom на сайте Hackage. Если это больше, чем просто эксперимент, чтобы проверить, сможете ли вы это сделать, вы можете вместо этого использовать эту библиотеку.