
Hi, I was just messing with randomIO for no particular reason, and it suddenly caused a stack overflow which would only go away after restarting ghci. Here's what I see in ghci 6.8.2 http://moonpatio.com/fastcgi/hpaste.fcgi/view?id=1642 mmorrow posted the same using ghci 6.10.1 which gave the same stack overflow Anyone got any idea what causes this funny behavior? - Tim

On Sun, 2009-03-01 at 00:34 +0100, timtoorop@quicknet.nl wrote:
Hi, I was just messing with randomIO for no particular reason, and it suddenly caused a stack overflow which would only go away after restarting ghci.
Here's what I see in ghci 6.8.2 http://moonpatio.com/fastcgi/hpaste.fcgi/view?id=1642
mmorrow posted the same using ghci 6.10.1 which gave the same stack overflow
Anyone got any idea what causes this funny behavior?
class Random a where ... snip ... randomIO :: IO a randomIO = getStdRandom random getStdRandom :: (StdGen -> (a,StdGen)) -> IO a getStdRandom f = atomicModifyIORef theStdGen (swap . f) where swap (v,g) = (g,v) So what happens when we do _ <- randomIO _ <- randomIO _ <- randomIO is that we're calling getStdRandom random many times and not inspecting the random numbers generated. That means the IORef containing the global rnd state (theStdGen) is now an unevaluated thunk that looks rather like: snd . random . snd . random . snd . random $ mkStdRNG 0 Now, if instead of doing it 3 times like above, you do it 100,000 times then you get a very big thunk indeed. Evaluating this thunk overflows the stack. Calling randomIO again and evaluating the result does not help. The internal IORef still contains the stack-overflowing thunk. Once in this situation we're stuffed. We've thrown away all the values that we could force that would let us evaluate the thunk when it was still small enough to do so. This problem could probably be fixed by adjusting the definition of getStdRandom like: getStdRandom :: (StdGen -> (a,StdGen)) -> IO a getStdRandom f = atomicModifyIORef theStdGen $! (swap . f) where swap (v,g) = g `seq` (g,v) Though even that may not do it. The StdGen data and stdNext functions may not be strict enough. data StdGen = StdGen Int32 Int32 It's not strict in the Int32 fields. I doubt that it needs to be so lazy. Duncan

On Mon, Mar 02, 2009 at 10:02:58PM +0000, Duncan Coutts wrote:
This problem could probably be fixed by adjusting the definition of getStdRandom like:
getStdRandom :: (StdGen -> (a,StdGen)) -> IO a getStdRandom f = atomicModifyIORef theStdGen $! (swap . f) where swap (v,g) = g `seq` (g,v)
Though even that may not do it. The StdGen data and stdNext functions may not be strict enough.
data StdGen = StdGen Int32 Int32
It's not strict in the Int32 fields. I doubt that it needs to be so lazy.
If I was right a few years ago, making getStdRandom more strict is indeed enough, although it does change the behaviour of x <- randomRIO undefined which probably noone cares about anyway. There is also already a ticket for this and another problem: http://hackage.haskell.org/trac/ghc/ticket/427 Groeten, Remi
participants (3)
-
Duncan Coutts
-
Remi Turk
-
timtooropï¼ quicknet.nl