[Haskell-cafe] working with Random.randoms
Daniel Fischer
daniel.is.fischer at web.de
Fri Jun 13 13:05:21 EDT 2008
Am Freitag, 13. Juni 2008 18:38 schrieb Stephen Howard:
> Hi List,
>
> I am a newcomer doing my obligatory struggling with Haskell's type
> system, 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
>
> I'm expecting that I ought to be able to pass this action an integer and
> get back a random string that long (given, not all characters may be
> printable).
>
> But GHCI tells me:
>
> RandomTest.hs:7:4:
> Couldn't match `[]' against `IO'
> Expected type: []
> Inferred type: IO
> In a 'do' expression: g <- getStdGen
> In the definition of `random_test':
> random_test n = do
> g <- getStdGen
> take n (randoms g) :: String
>
> And yet, when I run these lines in GHCI by hand, things seem to work
> (though the string is the same set of random characters each time,
> another bit that I need to solve):
>
> Prelude> :module Random
> Prelude Random> g <- getStdGen
> Prelude Random> take 5 (randoms g)::String
> "\1025049\315531\882767\1032009\334825"
>
>
> I'm guessing that randoms is returning an IO type but I'm not sure how
No, getStdGen is what's in IO, it has type IO StdGen. Since you can't get rid
of IO safely, the type of random_test must be Int -> IO String.
Best practice is to separate into a pure part:
pure_random_test :: Int -> StdGen -> String
pure_random_test n g = take n (randoms g)
and the IO bound part:
random_test :: Int -> IO String
random_test n = do
g <- getStdGen
return $ pure_random_test n g
or, if we like it better:
random_test n = fmap (pure_random_test n) getStdGen
> 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.
>
> Where am I going wrong?
You must put the String (take n (randoms g)) into the IO monad.
The way it works in ghci is due to the fact, that in ghci, you are basically
in an IO loop/do-block.
When you type
g <- getStdGen
the action is performed, and the result is bound to the identifier g.
When you then type
take 5 (randoms g),
it's transformed into
do .....
let it = take 5 (randoms g)
print it
return it
Within one session, all calls to getStdGen return the same StdGen, that's why
you always get the same sequence of random Chars.
>
> thanks,
> Stephen
HTH,
Daniel
More information about the Haskell-Cafe
mailing list