Consider the following code that is supposed to print out random numbers:
import System.Random.Mersenne
main =
do g <- (newMTGen Nothing)
xs <- (randoms g) :: IO [Double]
mapM_ print xs
When run, I get a segmentation fault error. That is unsurprising, since the function 'randoms' produces an infinite list. Suppose I wanted to print out only the first ten values of xs. How could I do that? xs has type IO [Double], and I think I want a variable of type [IO Double]. What operators exist to convert between the two.
IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.
The usual way to convert an Int to a Double is to use fromIntegral , which has the type (Integral a, Num b) => a -> b . This means that it converts an Integral type ( Int and Integer ) to any numeric type b , of which Double is an instance.
The I/O monad contains primitives which build composite actions, a process similar to joining statements in sequential order using `;' in other languages. Thus the monad serves as the glue which binds together the actions in a program.
Haskell is a pure language Moreover, Haskell functions can't have side effects, which means that they can't effect any changes to the "real world", like changing files, writing to the screen, printing, sending data over the network, and so on.
If you get a segmentation fault error, and you didn't use the FFI or any functions with unsafe
in their name, that's not unsurprising, in any situation! It means there's a bug with either GHC, or a library you're using is doing something unsafe.
Printing out an infinite list of Double
s with mapM_ print
is perfectly fine; the list will be processed incrementally and the program should run with constant memory usage. I suspect there is a bug in the System.Random.Mersenne
module you're using, or a bug the C library it's based on, or a problem with your computer (such as faulty RAM).1 Note that newMTGen
comes with this warning:
Due to the current SFMT library being vastly impure, currently only a single generator is allowed per-program. Attempts to reinitialise it will fail.
You might be better off using the provided global MTGen
instead.
That said, you can't convert IO [Double]
into [IO Double]
in that way; there's no way to know how long the resulting list would be without executing the IO
action, which is impossible, since you have a pure result (albeit one that happens to contain IO
actions). For infinite lists, you could write:
desequence :: IO [a] -> [IO a]
desequence = desequence' 0
where
desequence n m = fmap (!! n) m : desequence (n+1) m
But every time you execute an action in this list, the IO [a]
action would be executed again; it'd just discard the rest of the list.
The reason randoms
can work and return an infinite list of random numbers is because it uses lazy IO with unsafeInterleaveIO
. (Note that, despite the "unsafe" in the name, this one can't cause segfaults, so something else is afoot.)
1 Other, less likely possibilities include a miscompilation of the C library, or a bug in GHC.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With