[Haskell-cafe] Re: working with Random.randoms

Stephen Howard stephen at enterity.com
Wed Jun 18 15:39:02 EDT 2008

Thanks for the replies.  This was my solution:

module RandomTest ( random_test ) where

import Random

random_test :: Int -> IO String
random_test n = do
    g <- newStdGen
    return $ take n (randomRs printable_ascii g)
  where printable_ascii = ('!','~')

The "struggling with the type system" was supposed to be 
tongue-in-cheek.  I trust it, it just takes some time to get used to 
it.  And I appreciate Dan's comments about separating the pure code from 
the non-pure, but in this case the code was succinct enough that one 
more layer of functions seemed to do more harm than good when it came to 

- Stephen

Jon Fairbairn wrote:
> Stephen Howard <stephen at enterity.com> writes:
>> I am a newcomer doing my obligatory struggling with
>> Haskell's type system, 
> That's your mistake. Don't struggle with the type system,
> the type system is your friend; when it tells you you are
> doing something wrong, it's usually right.
>> and I've got a nut I've not been able to crack.  Given:
>> import Random
>> random_test :: Int -> String
>> random_test n = do
>>    g <- getStdGen
>>    take n (randoms g)::String
> My immediate reaction on seeing this is that "do" is for
> manipulating monads, but the only monad you've indicated in
> the type is [] (from String = [Char]), and that's probably
> an accident.
> In GHCi:
> Prelude> :t Random.getStdGen
> Random.getStdGen :: IO System.Random.StdGen
> What this says is that getStdGen isn't a function, which is
> to say it doesn't always return the same value (ie it isn't
> pure -- it wouldn't be much use if it were!). In effect it
> uses the real world to get a new value, and such things are
> kept safely in the IO monad. In C, everything is in the IO
> monad; there's no way of telling from the type whether
> something is pure or not¹. In Haskell (apart from some
> ugliness that's supposed to stay hidden) you have to
> distinguish between pure and impure, and the type checker
> keeps track of all this for you.
>> And yet, when I run these lines in GHCI by hand,
> The top level of GHCi is IO (which shouldn't come as a
> surprise!)
>> things seem to work (though the string is the same set of
>> random characters each time, another bit that I need to
>> solve
> That's a somewhat obscure aspect of GHCi, I think, to do
> with "not reverting top-level expressions".  If you do this:
> Prelude> :set +r
> Prelude> g <- Random.getStdGen -- what's the type?
> 1954047482 7573
> Prelude> g <- Random.getStdGen -- what's the type?
> 1626678354 7697
> Prelude> 
> you see that you get a different StdGen each time.
>> I'm guessing that randoms is returning an IO type but I'm
>> not sure how to go about extracting the String to return to
>> the calling action.  Changing the type signature to Int ->
>> IO  String only gives me a different error.
> If you do any IO, you've done some IO! So you need to lift
> out the StdGen and pass that to the functions that you want
> to use it.
> main :: IO()
>    do gen <- getStdGen
>       the_list <- real_programme gen
>       print the_list
> You should be able to deduce from the fact that the first
> argument of real_programme here is of type StdGen (not IO
> anything) and its result type is [something] that
> real_programme is pure, and gen has only one value
> throughout. So if you want more than one random list out of
> it, you either need to use Random.split or pass more than
> one gen in.
> [1] Were you truly perverse, you could define your own
> libraries in Haskell so that YourInt = IO Int; YourDouble =
> IO Double etc, and make appropriate classes in place of Num
> &c (hiding the proper ones), so that
> + :: YourInt -> YourInt -> YourInt
> and so on (you'd have to define your own Bool and if, too,
> but Haskell can do that). Then the type checker would
> overlook all sorts of mistakes that it could otherwise have
> caught.

More information about the Haskell-Cafe mailing list