[Haskell-cafe] Space usage problems
Ian Lynagh
igloo at earth.li
Tue Jan 10 11:44:33 EST 2006
Hi all,
I am having space issues with some decompression code; I've attached a
much simplified version as Test1.hs.
At the bottom (foo/bar) is the equivalent of deflate. This should be a
standalone module which doesn't know about the rest.
In the middle (readChunks) is the equivalent of gunzip. It repeatedly
calls foo until there is no more input left.
At the top is a simple main function that calls them.
If I do
dd if=/dev/zero of=data bs=1000 count=3000" # making data around 3MB
ghc --make Test1 -o Test1 -O -Wall
./Test1
then in top I see Test1 increasing memory usage to around 150MB. I think
this is because the "let (ys, zs) = foo xs" means zs holds on to xs
(it's hard to be sure as compiling for profiling is too happy to change
the behaviour).
I tried (Test2) changing foo to be a monad transformer over the calling
monad, so the caller's remaining input was updated as we went along, but
(as well as memory usage not obviously being fixed) this is giving me a
stack overflow.
Has anyone got any suggestions for making a constant space, constant
stack version?
Thanks
Ian
-------------- next part --------------
module Main (main) where
import Control.Monad (liftM)
import Control.Monad.State (State, runState, evalState, get, put)
main :: IO ()
main = do xs <- readFile "data"
ys <- readFile "data"
print (evalState readChunks xs == ys)
---
type FirstMonad = State String
readChunks :: FirstMonad String
readChunks = do xs <- get
if null xs then return []
else do let (ys, zs) = foo xs
put zs
rest <- readChunks
return (ys ++ rest)
---
type SecondMonad = State String
foo :: String -> (String, String)
foo = runState bar
bar :: SecondMonad String
bar = do inp <- get
case inp of
[] -> return []
x:xs -> do put xs
liftM (x:) bar
-------------- next part --------------
module Main (main) where
import Control.Monad (liftM)
import Control.Monad.Trans (lift)
import Control.Monad.State (StateT, evalStateT, State, evalState, get, put)
main :: IO ()
main = do xs <- readFile "data"
ys <- readFile "data"
print (evalState readChunks xs == ys)
---
type InnerMonad = State String
readChunks :: InnerMonad String
readChunks = do xs <- get
if null xs then return []
else do ys <- foo get put
rest <- readChunks
return (ys ++ rest)
---
data St m = St { get_inp :: m String, put_inp :: String -> m () }
type OuterMonad m = StateT (St m) m
foo :: Monad m => m String -> (String -> m ()) -> m String
foo getter putter = evalStateT bar (St getter putter)
bar :: Monad m => OuterMonad m String
bar = do st <- get
inp <- lift $ get_inp st
case inp of
[] -> return []
x:xs -> do lift $ put_inp st xs
liftM (x:) bar
More information about the Haskell-Cafe
mailing list