
Hi, I have been having a problem for some time, maybe this is a simple obvious question, but I would like your help on this. I give only what I think is the crux of the problem, just to keep this mail short and avoid unnecessary details. Consider, step (n, x:xs) = step (n+x, xs) main' = step (1, repeat 1) I think, if you evaluate main', you'd run out of heap space (couldn't totally verify because my hugs crashed on my windows machine!). Now have another step' step' n (x:xs) | n == 0 = 0 | otherwise = step' (n+x) xs main'' = step' 1 (repeat 1) Now main'' continues forever, but doesn't cause hugs to run out of heap.What' the reason that, while both main' and main'' run forever, the first causes hugs to run out of heap while second doesn't. Thanks, bye. - Srineet.

"Srineet"
Now [main2] continues forever, but doesn't cause hugs to run out of heap.What' the reason that, while both [main1] and [main2] run forever, the first causes hugs to run out of heap while second doesn't.
referring to the following program (slightly adapted for compatibility with HOPS/MHA):
step1 :: [Int] -> Int -> Int step1 (x:xs) n = step1 xs (n+x)
main1 :: Int main1 = step1 (repeat 1) 1
step2 :: [Int] -> Int -> Int step2 (x:xs) n | n == 0 = 0 | otherwise = step2 xs (n+x)
main2 :: Int main2 = step2 (repeat 1) 1
The reason is that the addition in step1 is deferred lazily, since its result is never needed. Therefore, unreduced additions accumulate. In contrast, the result of the addition in step2 is needed for comparison in ``n == 0'' --- this forces evaluation of n. I have produced two animations (hold down the space bar in ghostview to get the effect ;-), available at: http://ist.unibw-muenchen.de/kahl/MHA/Srineet_main1.ps.gz http://ist.unibw-muenchen.de/kahl/MHA/Srineet_main2.ps.gz A remedy might be to force sequentialisation:
step1' (x:xs) n = let n' = n+x in n' `seq` step1 xs n'
Hope that helps! Wolfram http://ist.unibw-muenchen.de/kahl/ http://ist.unibw-muenchen.de/kahl/HOPS/

Thanks, but oops, that doesn't solve my real problem. Ok, let me stop trying to simplify and put the relevanty parts of my original code. Will lead to a longer mail. With a space leak: ------------------ This is what I had earlier. I have a type called PTState which is,
type PTState = (PTBitmaps, Randoms, Helicopters) "Randoms" is a type synonym for [Int]. "PTBitmaps" is not so relevant here, neither is Helicopters.
And this used to be the main loop (you can skip the first three lines, the main part is "loop"). mainLoop = do w <- openWindowEx "Paratrooper 1" Nothing (Just (wWidth, wHeight)) DoubleBuffered (Just 100) bmps <- loadPTBitmaps --load bmp files rs <- randomRsIO (1, 20) -- random numbers let loop st = do getWindowTick w let (ns, gs) = step st; g = foldr overGraphic emptyGraphic gs in do setGraphic w g; loop ns loop (initState bmps rs) Btw, I am using the hugs graphics library here. I'll just give the type of some functions: mainLoop:: IO() step :: PTState->PTState -- this is like updating the state and passing it back to "loop" again. randomRsIO::[Int] is supposed to return a lazily evaluated infinite list of random numbers. setGraphic :: Window -> Graphic -> IO() -- just draws a "graphic" on screen. initState :: PTBitmaps -> Randoms -> PTState -- just initializes the state. No Space Leak: ----------------- Now I removed the randoms from PTState: and started passing it as a separate parameter to "loop" and "step": So the new PTState is just (PTBitmaps, Helicopters)
main' = do w <- openWindowEx "Paratrooper 1" Nothing (Just (wWidth, wHeight)) DoubleBuffered (Just 100) bmps <- loadPTBitmaps --load bmp files rs <- randomRsIO (1, 20) -- random numbers loop w rs (initState bmps)
loop w rs st = do getWindowTick w let (ns, gs) = step st (take numHelicopters rs); g = foldr overGraphic emptyGraphic gs in do setGraphic w g; loop w (drop numHelicopters rs) ns
Why did the space leak go away? - Srineet. More info: In the earlier version I used to use the following function to extract random numbers from the state:
stGetRandoms :: Int -> PTState -> (Randoms, PTState) stGetRandoms num (bmps, rs, hcs) = (take num rs, (bmps, drop num rs, hcs))
----- Original Message -----
From:
"Srineet"
writes: Now [main2] continues forever, but doesn't cause hugs to run out of heap.What' the reason that, while both [main1] and [main2] run forever,
the
first causes hugs to run out of heap while second doesn't.
referring to the following program (slightly adapted for compatibility with HOPS/MHA):
step1 :: [Int] -> Int -> Int step1 (x:xs) n = step1 xs (n+x)
main1 :: Int main1 = step1 (repeat 1) 1
step2 :: [Int] -> Int -> Int step2 (x:xs) n | n == 0 = 0 | otherwise = step2 xs (n+x)
main2 :: Int main2 = step2 (repeat 1) 1
The reason is that the addition in step1 is deferred lazily, since its result is never needed. Therefore, unreduced additions accumulate.
In contrast, the result of the addition in step2 is needed for comparison in ``n == 0'' --- this forces evaluation of n.
I have produced two animations (hold down the space bar in ghostview to get the effect ;-), available at:
http://ist.unibw-muenchen.de/kahl/MHA/Srineet_main1.ps.gz http://ist.unibw-muenchen.de/kahl/MHA/Srineet_main2.ps.gz
A remedy might be to force sequentialisation:
step1' (x:xs) n = let n' = n+x in n' `seq` step1 xs n'
Hope that helps!
Wolfram
http://ist.unibw-muenchen.de/kahl/ http://ist.unibw-muenchen.de/kahl/HOPS/

[Metacomment: the only way to really answer your question is to use one of the debugging tools mentioned previously in the space leak threads. For large programs, anything else is just a list of guesses.] I think the space leak lies in the code you did not show us. What does step look like? If it looks like this: step (a,b,c) = (a',b',c') where ... then the space leak is _not_ caused by bundling up the state - you could move the take and drop inside the definition of step (which would make your code a bit cleaner and more modular too.) How do you access the list of helicopters inside step? It could be that one of the random numbers you're asking for isn't being evaluated and you're being left with a thunk like this: head randoms where, in the first version of your code, randoms is an infinite list and, in the second version, it is a small, finite list. Maybe all you need to do is change the definition of step to: step (a,b,c) = c' `seq` (a',b',c') where ... Finally, if this doesn't work (and debugging tools fail you) my experience of arcade games in Haskell is that nearly all the state is used to generate an image at each step. If your problem is a strictness bug, you might be able to find it just by thinking about what parts of the state are _not_ used to generate the image. -- Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/

Thanks! Indeed some random numbers might not get always evaluated, the way the code is in the first version. Lemme just put it here, The function that steps one helicopter:
stepHC :: Int -> Helicopter -> Helicopter
-- handling the case of a helicopter going left to right stepHC r (HC (Just x, y) DRight) | x >= (hcRight - hcBmpWd) = HC (Nothing, y) DRight | otherwise = HC (Just (x+hcStep), y) DRight stepHC r (HC (Nothing, y) DRight) | r > 1 = HC (Nothing, y) DRight | otherwise = HC (Just hcLeft, y) DRight
-- now a helicopter going right to left stepHC r (HC (Just x, y) DLeft) | x <= (hcLeft + hcStep) = HC (Nothing, y) DLeft | otherwise = HC (Just (x - hcStep), y) DLeft stepHC r (HC (Nothing, y) DLeft) | r > 1 = HC (Nothing, y) DLeft | otherwise = HC (Just (hcRight - hcBmpWd),y) DLeft
The function that steps all my helicopters:
stepHCs :: PTState -> PTState stepHCs s = let (rs, ns) = stGetRandoms numHelicopters s fns = map stepHC rs hcs = zipWith ($) fns (stGetHCs ns)
I have already given "stGetRandoms". It is:
stGetRandom :: PTState -> (Int, PTState) stGetRandom (bmps, r:rs, hcs) = (r, (bmps, rs, hcs))
Now, as we see, the random number doesn't always get evaluated. So I tried
two things:
1. Putting "seq" in stGetRandoms, so that "r" will be evaluated. Didn't help
:(
2. In stepHC above, putting "r > 0 && " in every guard (hoping "r" will
always get evaluated). But even this doesn't remove the space leak.
I still think, its something to do with this list of random numbers, since
removing it out of the PTSTate tuple and passing it as a parameter, has
removed the space leak. I wuld like to get to the bottom of this, just so
that I understand why there's a leak, and in general increase my Haskell
knowledge. Please help.
Thanks. Bye.
- Srineet.
P.S. I've only got HOOD, and yes, when I try and observe the state, the
random list component, is a huge infinite list with many unevaluated numbers
first, and some evaluated numbers sprinkled here and there. But why is this
happening?
----- Original Message -----
From: "Alastair David Reid"
[Metacomment: the only way to really answer your question is to use one of the debugging tools mentioned previously in the space leak threads. For large programs, anything else is just a list of guesses.]
I think the space leak lies in the code you did not show us.
What does step look like? If it looks like this:
step (a,b,c) = (a',b',c') where ...
then the space leak is _not_ caused by bundling up the state - you could move the take and drop inside the definition of step (which would make your code a bit cleaner and more modular too.)
How do you access the list of helicopters inside step? It could be that one of the random numbers you're asking for isn't being evaluated and you're being left with a thunk like this:
head randoms
where, in the first version of your code, randoms is an infinite list and, in the second version, it is a small, finite list.
Maybe all you need to do is change the definition of step to:
step (a,b,c) = c' `seq` (a',b',c') where ...
Finally, if this doesn't work (and debugging tools fail you) my experience of arcade games in Haskell is that nearly all the state is used to generate an image at each step. If your problem is a strictness bug, you might be able to find it just by thinking about what parts of the state are _not_ used to generate the image.
-- Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/
participants (3)
-
Alastair David Reid
-
kahl@heraklit.informatik.unibw-muenchen.de
-
Srineet