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 <[EMAIL PROTECTED]> 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.


_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to