[Haskell-cafe] Help mixing pure and IO code

Luke Palmer lrpalmer at gmail.com
Mon Nov 30 22:53:44 EST 2009


On Mon, Nov 30, 2009 at 8:36 PM, Hector Guilarte <hectorg87 at gmail.com> wrote:
> One time I needed to do use a random number in some places of a completly
> pure program so I made a infinite list of random numbers and passed it
> around all the time in the functions as they where called, using the head of
> the list I passed to the function whenever I needed a random number and
> returning a tuple which it's second element was the tail of the random
> numbers list e.g.
>
> f:: [int] -> (a,[Int])
> f randomList =
>     let usedRandomNumber = g $ head randomList
>     in (usedRandomNumber,(tail randomList))
>
> or even something like:
> f:: [int] -> (a,[Int])
> f randomList =
>     let (usedRandomNumber,newRandomList) = g randomList
>     in (usedRandomNumber,newRandomList)

This pattern can be encapsulated in a monad:

newtype RandM a = RandM { unRandM :: [Int] -> (a,[Int]) }

instance Monad RandM where
    return x = RandM $ \randomList -> (x, randomList)
    m >>= g = RandM $ \randomList ->
      let (x, newRandomList) = unRandM m randomList
      in unRandM (g x) newRandomList

getRandom :: RandM Int
getRandom = RandM $ \(randomNumber:randomList) -> (randomNumber, randomList)

See the similarity?

Of course, there is no need to implement this yourself.  It is already
implemented as State [Int].  And as long as you are doing that, you
might as well use Rand from the MonadRandom package.  In fact, I have
argued that you should use MonadRandom instead of the lower-level
System.Random whenever possible:
http://lukepalmer.wordpress.com/2009/01/17/use-monadrandom/

Luke


More information about the Haskell-Cafe mailing list