module Main where import Control.Monad.Exception.Asynchronous (Exceptional(Exceptional), force, pure, throwMonoid, broken, result, exception, ) import Control.Monad (mplus, ) import Data.Monoid (Monoid, mappend, mempty, ) convert :: [Either String a] -> Exceptional String [a] convert = emconcat . map (force . either throwMonoid (pure . (:[]))) emconcat :: Monoid a => [Exceptional e a] -> Exceptional e a emconcat = force . foldr (\(Exceptional e a) ~(Exceptional es as) -> Exceptional (mplus e es) (mappend a as)) (pure mempty) econcat :: [Exceptional e a] -> Exceptional e [a] econcat = force . foldr (\(Exceptional e a) ~(Exceptional es as) -> Exceptional (mplus e es) (a:as)) (pure []) convert0 :: [Either String a] -> Exceptional String [a] convert0 = force . -- not quite mconcat, because we need lazy matching on the right operand foldr (\a b -> mappend a (force b)) (pure []) . map (either throwMonoid (pure . (:[]))) convert1 :: [Either String a] -> Exceptional String [a] convert1 = force . foldr (\ea -> force . either (mappend . throwMonoid) (\entry -> fmap (entry:)) ea) (pure []) -- the String argument prevents caching and thus a space-leak infinite :: String -> [Either String Integer] infinite msg = map Right (iterate (1+) 0) ++ [Left msg] -- the String argument prevents caching and thus a space-leak infiniteExc :: String -> [Exceptional String Integer] infiniteExc msg = map (Exceptional Nothing) (iterate (1+) 0) ++ [broken msg 0] skip :: [a] -> [a] skip = map head . iterate (drop 1000) spaceLeak0 :: IO () spaceLeak0 = let r = convert $ infinite "bla" e = exception r xs = result r in do mapM_ print $ skip xs print e spaceLeak1 :: IO () spaceLeak1 = let Exceptional e xs = convert $ infinite "bla" in do mapM_ print $ skip xs print e spaceLeak2 :: IO () spaceLeak2 = let Exceptional e xs = econcat $ infiniteExc "bla" in do mapM_ print $ skip xs print e noSpaceLeak0 :: IO () noSpaceLeak0 = let r = convert $ infinite "bla" _e = exception r xs = result r in mapM_ print $ skip xs noSpaceLeak1 :: IO () noSpaceLeak1 = let Exceptional _e xs = convert $ infinite "bla" in mapM_ print $ skip xs {- ee-test +RTS -M32m -c30 -RTS -} main :: IO () main = spaceLeak2