{-# LANGUAGE GeneralizedNewtypeDeriving, BangPatterns #-}

module Main where

import Control.Monad.State.Strict

data MyState = MyState { val :: String }

newtype Foo a = Foo { run :: StateT MyState IO a }
	deriving (
		Monad,
		MonadState MyState,
		MonadIO
	)

main :: IO ()
main = evalStateT (run test) (MyState "")
	
test :: Foo ()
test = mapM_ work [1..100000]    -- massive memory leak
--test = mapM_ work' [1..100000] -- constant space

readSomeFile :: Foo String
readSomeFile = liftIO $ readFileStrict "/etc/passwd"

work :: Integer -> Foo ()
work _ = do
	v <- readSomeFile
	modify $ \s -> s { val = v }

work' :: Integer -> Foo ()
work' n = do
	_ <- readSomeFile
	modify $ \s -> s { val = show n }

readFileStrict :: FilePath -> IO String
readFileStrict file = do
	s <- readFile file
	length s `seq` return s
