[Haskell-cafe] Re: working with Random.randoms
Jon Fairbairn
jon.fairbairn at cl.cam.ac.uk
Sat Jun 14 06:30:38 EDT 2008
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.
--
Jón Fairbairn Jon.Fairbairn at cl.cam.ac.uk
http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2008-04-26)
More information about the Haskell-Cafe
mailing list