[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
legibility.
- 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