Простая монада Haskell - случайное число

Я пытаюсь расширить код в этом сообщении (принятый ответ), чтобы я мог вызовите randomGen2, чтобы получить случайное число, на основе функции randomGen, которая принимает начальное число в качестве аргумента. Но каждый раз, когда я вызываю randomGen2, несмотря на то, что возвращаю Int, я получаю сообщение об ошибке о том, что мне не удалось напечатать Random (когда на самом деле я пытаюсь напечатать только Int).

<interactive>:3:1:
    No instance for (Show (Random Int))
      arising from a use of `print'
    Possible fix: add an instance declaration for (Show (Random Int))
    In a stmt of an interactive GHCi command: print it

Вот код:

import Control.Monad.State

type Seed = Int

randomGen :: Seed -> (Int, Seed)
randomGen seed = (seed,seed+1)

type Random a = State Seed a

randomGen2 :: Random Int
randomGen2 = do
        seed <- get
        let (x,seed') = randomGen seed
        put seed'
        return x

Любые идеи?

Обновление - ожидаемое поведение. Я надеюсь, что смогу что-то сделать с помощью интерпретатора (например, GHCI) -

> getRandomInit 1
> -- some other stuff, e.g. 2 + 3
> getRandom

то есть я могу настроить свою функцию getRandom с семенем, которое затем сохраняет семя, используя put, затем эта функция возвращается и завершается. Затем я делаю что-то другое, затем снова вызываю getRandom, и семя извлекается из монады, где оно было сохранено.


person Sam Heather    schedule 11.05.2014    source источник
comment
getRandomInit - это System.Random.setStdGen. Обратите внимание, что setStdGen принимает StdGen, а не Int. Вы можете создать его из Int с помощью mkStdGen. getRandom это System.Random.randomIO. Ознакомьтесь с документацией для получения более подробной информации. Также имейте в виду, что если вам нужно глобальное состояние, оно должно находиться внутри IO - вы не можете использовать State.   -  person user2407038    schedule 12.05.2014


Ответы (1)


randomGen2 возвращает Random Int, который является State Seed Int, поэтому вам нужно будет использовать runState, чтобы получить результат, указав начальное значение, например.

runState randomGen2 1

Если вы хотите и дальше повторять применение randomGen2, вы можете создать такую ​​функцию, как:

genRandoms :: Seed -> [Int]
genRandoms s = let (v, s') = runState randomGen2 s in v : genRandoms s'

или вы можете использовать sequence:

genRandoms :: Seed -> [Int]
genRandoms s = fst $ runState (sequence (repeat randomGen2)) s 
person Lee    schedule 11.05.2014
comment
Хорошо, теперь он выполняется, но мне возвращается (1,2), а не только 1 (что странно, поскольку я думал, что в своем коде я возвращаю только int X из группы (x, seed '), и он остается неизменным каждый раз, т.е. когда я запускаю его дважды, я получаю (1,2) оба раза, а не (1,2), (2,3) (который я должен получить, если семя было сохранено и извлечено)? - person Sam Heather; 11.05.2014
comment
@SamHeather - runState возвращает пару, содержащую результат и значение конечного состояния. Если вам просто нужен результат, вы можете извлечь его, используя fst, например. fst $ runState randomGen2 1 - person Lee; 11.05.2014
comment
хорошо, это касается первого вопроса, но как я могу запустить это снова с измененным значением для состояния? Я думал, что смогу продолжать выполнять randomGen2 и каждый раз получать другой случайный Int, потому что семя изменилось и было сохранено? - person Sam Heather; 11.05.2014
comment
@SamHeather - Я обновил ответ - это то, что вы ищете? - person Lee; 11.05.2014
comment
@Lee, могу ли я узнать ваше мнение о том, будет ли это лучший способ для меня получить список случайных чисел в Haskell из семени, которое я передаю и которым я управляю? Кроме того, это все еще не то поведение, которого я ожидал - я обновил вопрос, чтобы уточнить - извините, я не очень ясно. Даже не уверен, возможно ли это в Haskell, и моя книга не помогает! - person Sam Heather; 11.05.2014