
Hal Daume III writes: | but when i replace: | | modifyIORef r <E> | | with | | v <- readIORef r | writeIORef r $! <E> | | I no longer run into this heap problem and the program runs much | more quickly. Yes. When (f $! x) is evaluated, first x is forced to Weak Head Normal Form, and then (f x) is evaluated. In this case, (writeIORef r $! <E>) is evaluated early, thanks to the strict sequencing of actions in the IO monad, so <E> is evaluated early too. You should get the same result with modifyIORef r $! <E> | even if I use (modifyIORef f (\x -> id $! <E> x)), which I thought | would fix it, there is still a heap problem. That's different, because the application of ($!) does not get caught up in the sequencing of actions. In answer to the subject line, modifyIORef updates a reference strictly, but the thing the reference refers to may be a suspended computation. In this case, after the modifyIORef the reference points to a suspension of (\x -> id $! <E> x) the_thing_previously_pointed_to and the evaluation hasn't yet reached the ($!).