[Haskell-cafe] Using MonadRandom with QuickCheck

Magnus Grindal Bakken magnusbakken at gmail.com
Sun Aug 21 19:38:00 UTC 2016


Is there some easy way to use the Gen type from QuickCheck with the
MonadRandom class?

Links to the packages in question:
https://hackage.haskell.org/package/MonadRandom
https://hackage.haskell.org/package/QuickCheck

Some background in case there's an easier way to solve the problem:
I'm toying around with an API for a simple turn-based board game. The
main type in my API is called GameState, and I'm trying to define an
Arbitrary instance for it so I can set up invariants with QuickCheck.
The Arbitrary instance should produce game states that are the result
of playing a random number of random moves.

At certain points in the gameplay the game itself needs to invoke some
randomness. I've designed the public game API to have basically just
two functions:

playAction :: ActionData -> GameState -> GameState
evaluateGameState :: MonadRandom m => GameState -> m GameState

The usage is supposed to be that the client first calls playAction
with an ActionData value that depends on the current move, and
afterwards calls evaluateGameState to evaluate whatever random events
need to happen at that point (e.g. reshuffling a deck of cards). That
way my main "action" logic doesn't need to concern itself with any
form of randomness.

I'm using MonadRandom from Control.Monad.Random because it seems like
a much nicer way to generate random numbers than using RandomGen
directly. However I can't figure out how to make it play nice with
QuickCheck. I can easily set up my Arbitrary instance to call
playAction an arbitrary number of times, but I can't call
evaluateGameState since it lives in the other monad. It would work if
Gen were an instance of MonadRandom, but I can't quite work out how to
write that instance since most functions on Gen only work if the
output type is an instance of Arbitrary, while MonadRandom needs to
work with any types that are part of the Random class. This part
works:

instance MonadRandom Gen where
    getRandomR = choose

But I don't know how to define the other functions on MonadRandom for Gen.

I think I might also be able to use the PropertyM monad transformer:
https://hackage.haskell.org/package/QuickCheck-2.9.1/docs/Test-QuickCheck-Monadic.html,
but monad transformers always confuse me so I haven't been able to
figure out how to do that yet either.

I've thought about rewriting the API to use the Gen type instead of
MonadRandom, but it feels kind of iffy to have the API depend on a
testing library.

Has anyone tried to use these libraries together before?


More information about the Haskell-Cafe mailing list