content: -- |
  -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
  -- License    : BSD3
  -- Maintainer : ivan.perez@keera.co.uk
  --
  -- This module contains operations on monadic streams that are asynchronous,
  -- i.e. that change the speed at which data enters or leaves the 'MSF'.
  module Data.MonadicStreamFunction.Async where
  
  -- Internal imports
  import Data.MonadicStreamFunction.InternalCore (MSF(MSF, unMSF))
  import Data.MonadicStreamFunction.Util         (MStream)
  
  -- |
  -- Concatenates a monadic stream of lists to a monadic stream.
  -- The stream of lists will be called exactly when new data is needed.
  --
  -- Example:
  --
  -- >>> let intstream = constS $ putStrLn "Enter a list of Ints:" >> readLn :: MStream IO [Int]
  -- >>> reactimate $ concatS intstream >>> arrM print
  -- Enter a list of Ints:
  -- [1, 2, 33]
  -- 1
  -- 2
  -- 33
  -- Enter a list of Ints:
  -- []
  -- Enter a list of Ints:
  -- []
  -- Enter a list of Ints:
  -- [1, 2]
  -- 1
  -- 2
  -- Enter a list of Ints:
  -- ...
  --
  -- Beware that @concatS msf@ becomes unproductive when @msf@ starts outputting
  -- empty lists forever. This is ok:
  --
  -- >>> let boolToList b = if b then ["Yes"] else []
  -- >>> let everyOddEmpty = count >>> arr (even >>> boolToList)
  -- >>> reactimate $ concatS everyOddEmpty >>> arrM print
  -- "Yes"
  -- "Yes"
  -- "Yes"
  -- "Yes"
  -- "Yes"
  -- ...
  --
  -- But this will be caught in a loop:
  --
  -- >>> let after3Empty = count >>> arr ((<= 3) >>> boolToList)
  -- >>> reactimate $ concatS after3Empty  >>> arrM print
  -- "Yes"
  -- "Yes"
  -- "Yes"
  -- ^CInterrupted.
  concatS :: Monad m => MStream m [b] -> MStream m b
  concatS msf = MSF $ \_ -> tick msf []
    where
      tick msf' (b:bs) = return (b, MSF $ \_ -> tick msf' bs)
      tick msf' []     = do
        (bs, msf'') <- unMSF msf' ()
        tick msf'' bs
  