summaryrefslogtreecommitdiff
path: root/compiler/utils/Stream.hs
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2012-01-26 16:01:04 +0000
committerSimon Marlow <marlowsd@gmail.com>2012-01-26 16:01:04 +0000
commit46a772f8efb7aa9d350227e8fd5d5809757c3f1e (patch)
treee12beccf2317e53f0a3b8fe3715e89da2d719cd4 /compiler/utils/Stream.hs
parent88745c9120f408e53ad1de2489963ede2ac9a668 (diff)
downloadhaskell-46a772f8efb7aa9d350227e8fd5d5809757c3f1e.tar.gz
Run the complete backend (Stg -> .S) incrementally on each StgBinding
This is so that we can process the Stg code in constant space. Before we were generating all the C-- up front, leading to a large space leak. I haven't converted the LLVM or C back ends to the incremental scheme, but it's not hard to do.
Diffstat (limited to 'compiler/utils/Stream.hs')
-rw-r--r--compiler/utils/Stream.hs97
1 files changed, 97 insertions, 0 deletions
diff --git a/compiler/utils/Stream.hs b/compiler/utils/Stream.hs
new file mode 100644
index 0000000000..2fa76d2345
--- /dev/null
+++ b/compiler/utils/Stream.hs
@@ -0,0 +1,97 @@
+-- -----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 2012
+--
+-- Monadic streams
+--
+-- -----------------------------------------------------------------------------
+
+module Stream (
+ Stream(..), yield, liftIO,
+ collect, fromList,
+ Stream.map, Stream.mapM, Stream.mapAccumL
+ ) where
+
+-- |
+-- @Stream m a b@ is a computation in some Monad @m@ that delivers a sequence
+-- of elements of type @a@ followed by a result of type @b@.
+--
+-- More concretely, a value of type @Stream m a b@ can be run using @runStream@
+-- in the Monad @m@, and it delivers either
+--
+-- * the final result: @Left b@, or
+-- * @Right (a,str)@, where @a@ is the next element in the stream, and @str@
+-- is a computation to get the rest of the stream.
+--
+-- Stream is itself a Monad, and provides an operation 'yield' that
+-- produces a new element of the stream. This makes it convenient to turn
+-- existing monadic computations into streams.
+--
+-- The idea is that Stream is useful for making a monadic computation
+-- that produces values from time to time. This can be used for
+-- knitting together two complex monadic operations, so that the
+-- producer does not have to produce all its values before the
+-- consumer starts consuming them. We make the producer into a
+-- Stream, and the consumer pulls on the stream each time it wants a
+-- new value.
+--
+newtype Stream m a b = Stream { runStream :: m (Either b (a, Stream m a b)) }
+
+instance Monad m => Monad (Stream m a) where
+ return a = Stream (return (Left a))
+
+ Stream m >>= k = Stream $ do
+ r <- m
+ case r of
+ Left b -> runStream (k b)
+ Right (a,str) -> return (Right (a, str >>= k))
+
+yield :: Monad m => a -> Stream m a ()
+yield a = Stream (return (Right (a, return ())))
+
+liftIO :: IO a -> Stream IO b a
+liftIO io = Stream $ io >>= return . Left
+
+-- | Turn a Stream into an ordinary list, by demanding all the elements.
+collect :: Monad m => Stream m a () -> m [a]
+collect str = go str []
+ where
+ go str acc = do
+ r <- runStream str
+ case r of
+ Left () -> return (reverse acc)
+ Right (a, str') -> go str' (a:acc)
+
+-- | Turn a list into a 'Stream', by yielding each element in turn.
+fromList :: Monad m => [a] -> Stream m a ()
+fromList = mapM_ yield
+
+-- | Apply a function to each element of a 'Stream', lazilly
+map :: Monad m => (a -> b) -> Stream m a x -> Stream m b x
+map f str = Stream $ do
+ r <- runStream str
+ case r of
+ Left x -> return (Left x)
+ Right (a, str') -> return (Right (f a, Stream.map f str'))
+
+-- | Apply a monadic operation to each element of a 'Stream', lazilly
+mapM :: Monad m => (a -> m b) -> Stream m a x -> Stream m b x
+mapM f str = Stream $ do
+ r <- runStream str
+ case r of
+ Left x -> return (Left x)
+ Right (a, str') -> do
+ b <- f a
+ return (Right (b, Stream.mapM f str'))
+
+-- | analog of the list-based 'mapAccumL' on Streams. This is a simple
+-- way to map over a Stream while carrying some state around.
+mapAccumL :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a ()
+ -> Stream m b c
+mapAccumL f c str = Stream $ do
+ r <- runStream str
+ case r of
+ Left () -> return (Left c)
+ Right (a, str') -> do
+ (c',b) <- f c a
+ return (Right (b, mapAccumL f c' str'))