[Haskell-cafe] How to update the RNG per call (State monad) when generating QuickCheck arbitraries?

Daniel Kahlenberg d.kahlenberg at googlemail.com
Wed Apr 27 11:14:16 CEST 2011


Hello,

> the final RNG state from the first execution of your code and passing it as the initial > state to the second

original intention of my question: How can I change the runOneRandom
function (with RNG updates) to return [ThingK True...] samples instead
of Int?

My solution so far:

> import Random
> import Control.Monad
> import qualified Control.Monad.State as S
> import Test.QuickCheck.Gen
> import Test.QuickCheck.Arbitrary

Each thing can have one of three types:

> data Ontology = Thing1 Bool
>               | ThingK Bool
>               deriving (Show, Eq)

> instance Arbitrary Ontology where
>    arbitrary =
>        oneof [ return $ Thing1 True
>              , return $ ThingK True
>              , return $ Thing1 False
>              , return $ ThingK False ]

Liked to have a state monad runner for my arbitrary things as in "Real World
Haskell", "Chapter 14. Monads" ("Random values in the state monad").

[RWH]:

> -- file: ch14/Random.hs
> type RandomState a = S.State StdGen a

[RWH]:

> -- file: ch14/Random.hs
> getRandom :: Random a => RandomState a
> getRandom =
>   S.get >>= \gen ->
>   let (val, gen') = random gen in
>   S.put gen' >>
>   return val

[RWH]:

> getOneRandom :: Random a => RandomState a
> getOneRandom = getRandom

[RWH]:

< runOneRandom :: IO Int
< runOneRandom = do
<   oldState <- getStdGen
<   let (result, newState) = S.runState getOneRandom oldState
<   setStdGen newState
<   return result

Updated RNG is used. TODO How to sort out empty lists.

> runOneRandom2 :: IO [Ontology]
> runOneRandom2 = do
>   oldState <- getStdGen
>   let (result, newState) = S.runState (getOneRandom :: RandomState Int) oldState
>   setStdGen newState
>   let result2 = unGen arbitrary newState 12 :: [Ontology]
>   return result2

To compare the behaviour: But the Random Number Generator isn't
updated... I liked to have different [Ontology] occasions per call:

> genArray :: [Ontology]
> genArray = unGen arbitrary (mkStdGen 42) 12 :: [Ontology]


On more question remains though: Is there a more haskellish way of
doing this, especially having behaviour more like the arbitrary
function with no empty samples allowed?

Cheers
Daniel

2011/4/26 Daniel Kahlenberg <d.kahlenberg at googlemail.com>:
> Oh thanks,
>
> hold on I'd like to have the genArray call generating distinctive
> results in one IO execution (meaning when
> I load the .lhs file in ghci):
>
> Prelude> genArray
> [ThingK True,Thing1 False]
>
> and when calling immediately again e. g.
>
> Prelude> genArray
> [Thing1 True]
>
> By now I only get one and the same again, i. e.:
>
> Prelude> genArray
> [ThingK True]
>
> Prelude> genArray
> [ThingK True]
>
> ...
>
> so I thought an adaptation of the `runTwoRandoms` approach as described
> in the RWH book could help.
>
> In other words the genArray should have similar behaviour as e. g. a
> `runOneRandom` function defined like:
>
>> getOneRandom :: Random a => RandomState a
>> getOneRandom = getRandom
>
>> runOneRandom :: IO Int
>> runOneRandom = do
>>   oldState <- getStdGen
>>   let (result, newState) = S.runState getOneRandom oldState
>>   setStdGen newState
>>   return result
>
> ... the rest of the code as in my first post...
>
> Testing it, different numbers expected as the RNG is updated each call:
>
> Prelude> runOneRandom
> 2033303743
>
> Prelude> runOneRandom
> -566930973
>
> ...
>
> Cheers
> Daniel
>
> 2011/4/26 Bryan O'Sullivan <bos at serpentine.com>:
>> On Tue, Apr 26, 2011 at 3:04 AM, Daniel Kahlenberg
>> <d.kahlenberg at googlemail.com> wrote:
>>>
>>> Thought getRandom function would be the best place to inject my unGen
>>> function
>>> call, but cannot get it to type-check:
>>
>> You haven't described what it is you're actually trying to do, and I'm
>> afraid your code doesn't help to understand that.
>



More information about the Haskell-Cafe mailing list