Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell monad: IO [Double] to [IO Double]

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.

like image 679
Gautam Avatar asked Apr 04 '12 19:04

Gautam


People also ask

What is IO () Haskell?

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.

How do you double a number in Haskell?

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.

How does IO Monad work?

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.

Does Haskell allow side effects?

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.


1 Answers

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 Doubles 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.

like image 95
ehird Avatar answered Oct 13 '22 04:10

ehird