[Haskell-cafe] Convert IO Int to Int

Sebastian Sylvan sebastian.sylvan at gmail.com
Wed Jun 10 09:08:15 EDT 2009

On Wed, Jun 10, 2009 at 12:55 PM, ptrash <ptrash at web.de> wrote:

>
> Hi,
>
> I have tried on the console to write
>
> x <- randomRIO(1,10)
> :t x
>
> Everythings fine and the type of x is
> x :: Integer
>

The type of x *in the context of an IO computation* is Integer. GHCi is
basically an IO computation.
Another example:

foo :: Integer -> Integer
foo x = x+1

main :: IO ()
main = do
x <- randomRIO (1,10)
print (foo x)

This is fine. In the context of the IO computation "main", x is bound to the
result of "randomRIO (1,10)", and you can pass it to functions expecting
Integer values (not IO Integer!). So in this way, and this way only, you can
access the Integer returned by an IO action. You can *not* access the
Integer returned by an IO action from within a normal function, *only* by by
binding it to a variable (with "<-") inside *another IO action*.

I'm not sure what text you're using to learn Haskell, but a very basic and
fundamental property of Haskell (and indeed 99% of why it's cool, IMO) is
that code which does side effects (like reading from a global random number
seed), and code which does not do side effects (i.e. functions which always
return the same result given the same input) are kept extremely separate.
This appears to be the source of your confusion. It's simply not possible to
do side effect inside a normal function, just like it's not possible to cast
an arbitrary integer to a pointer in Java - the language is designed to not
require it, and the benefits of being able to trust that your program obeys
certain properties are worth it.

>randomList :: Int -> [Integer]
>randomList 0 = []
>randomList n = do
>                            r <- randomRIO (1, 10)
>                            r:randomList(n-1)

In this code you're trying to do side effects from within a pure function.
This is *not* allowed. You must either make randomList an IO action (i.e
returning IO [Integer]), or remove any impurities from its
implementation. For example you can make randomList take a randon number
generator and use the random number generator to produce random values:

randomList :: (RandomGen g) -> Int -> g -> [Integer]
randomList 0 _ = []
randomList n generator = r : randomList (n-1) newGenerator
where (r, newGenerator) = randomR (1,10) generator

This is totally pure, since if you pass in the same random number generator
multiple times, you'll get the exact same
result. Note that randomR returns a random values and a new random number
generator (you wouldn't want to pass along the same one in the recursive
call to randomList as that would give you an identical random number each
time you use it!).

So where do you get the random number generator from? Well one way is to
make your own using "mkStdGen", which produces one from a seed (it will give
you an identical one given an identical seed). Another way is to use
"newStdGen" to generate one from within an IO action:

main :: IO ()
main = do
generator <- newStdGen
print ( randomList 10 generator )

The point, though, is that things having side effects (such as newStdGen)
can only be used in the context of something else having side effects. So
the "IO" type is "contagious", as soon as you use it in a function, then
that function must also return IO, and so on for anything using *that*
function and son.

--
Sebastian Sylvan
+44(0)7857-300802
UIN: 44640862
-------------- next part --------------
An HTML attachment was scrubbed...