[Haskell-cafe] Nested unsafePerformIO?

DavidA polyomino at f2s.com
Thu Apr 8 04:45:20 EDT 2010


Hi,

I am having difficulty debugging a troublesome stack overflow, which I
think might be related to calling unsafePerformIO from within the IO
monad.

So I have the following code:

import System.Random
import System.IO.Unsafe
import Data.Time.Clock

timedIterateIO :: Int -> (a -> a) -> a -> IO a
timedIterateIO durationSecs f x = do
    t0 <- getCurrentTime
    timedIterateIO' t0 x
    where duration' = fromIntegral durationSecs
          timedIterateIO' t0 x = do
              let y = f x
              t <- getCurrentTime
              let d = diffUTCTime t t0
              if d >= duration' then return y else timedIterateIO' t0
y

f x = unsafePerformIO $ do
    m <- randomRIO (1,2)
    return (m+x)

The idea of the timedIterateIO function is that it should repeatedly
apply f to x until a specified duration is up. The use case is for
game search, where I want to keep searching until time is up, and then
play the best move I've found at that point.

So the following works:
*Main> timedIterateIO 1 (+1) 0
45580
(1.01 secs, 360357840 bytes)

The following also seems to work:
*Main> unsafePerformIO $ timedIterateIO 1 f 0
67866
(1.25 secs, 394938540 bytes)

Now, in the real use case, I have another function, g let's say. It is
similar to f, in that it uses unsafePerformIO internally to get random
numbers. It's proven to work under normal circumstances, for example:
*Main> (!! 100) $ iterate g x
works, and completes in around a second.

However, the following doesn't work, failing with a stack overflow:
*Main> unsafePerformIO $ timedIterateIO 1 g x

Any ideas?

Thanks, David



More information about the Haskell-Cafe mailing list