[Haskell-cafe] Nested unsafePerformIO?

2010-04-08 Thread DavidA
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

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Nested unsafePerformIO?

2010-04-08 Thread Bas van Dijk
It looks like your timedIterateIO is too lazy.

When you pass it a function like (+1) what will happen is that a large
chunk of the form ...+1+1+1+1+1 is build up on your heap. When you
finally need its value the large chunk will be evaluated causing it to
push the '1' arguments on the stack. When there are too much '1's your
stack will eventually overflow.

Try evaluating the 'y' before calling timedIterateIO' again as in:

let y = f x
... y `seq` timedIterateIO' t0 y

I think the normal 'iterate' function also has this behaviour:

iterate (+1) 0 !! 1000

will cause your heap to be filled with lots of +1s and will finally
cause a stack overflow when it tries to evaluate the final value (I
haven't tried it so I may be wrong here).

regards,

Bas
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe