module Bio.Streaming.Furrow ( Furrow(..) , evertStream , afford , drain ) where import Bio.Prelude import Bio.Streaming {- | A tiny stream that can be afforded to incrementally. The streaming abstraction works fine if multiple sources feed into a small constant number of functions, but fails if there is an unpredictable number of such consumers. In that case, 'evertStream' should be used to turn each consumer into a 'Furrow'. It's then possible to incrementally 'afford' stuff to each 'Furrow' in a collection in a simple loop. To get the final value, 'drain' each 'Furrow'. -} newtype Furrow a m r = Furrow (Stream ((->) (Maybe a)) m r) deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MFunctor, MMonad) instance MonadThrow m => MonadThrow (Furrow a m) where throwM = Furrow . lift . throwM afford :: Monad m => Furrow a m b -> a -> m (Furrow a m b) afford (Furrow s) a = inspect s >>= \case Left b -> return (Furrow (pure b)) Right f -> return (Furrow (f (Just a))) drain :: Monad m => Furrow a m b -> m b drain (Furrow s) = inspect s >>= \case Left b -> return b Right f -> inspect (f Nothing) >>= \case Left b -> return b Right _ -> error "continuedAfterEOF" -- | Turns a function that consumes a stream into a furrow. Idea and -- some code stolen from \"streaming-eversion\". evertStream :: Monad m => (Stream (Of a) (Furrow a m) () -> Furrow a m b) -> Furrow a m b evertStream consumer = consumer cat where cat = lift (Furrow (yields id)) >>= maybe (pure ()) (\a -> wrap (a :> cat))