-- |
-- 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 :: forall (m :: * -> *) b. Monad m => MStream m [b] -> MStream m b
concatS MStream m [b]
msf = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \()
_ -> forall {m :: * -> *} {a} {a}.
Monad m =>
MSF m () [a] -> [a] -> m (a, MSF m a a)
tick MStream m [b]
msf []
  where
    tick :: MSF m () [a] -> [a] -> m (a, MSF m a a)
tick MSF m () [a]
msf' (a
b:[a]
bs) = forall (m :: * -> *) a. Monad m => a -> m a
return (a
b, forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \a
_ -> MSF m () [a] -> [a] -> m (a, MSF m a a)
tick MSF m () [a]
msf' [a]
bs)
    tick MSF m () [a]
msf' []     = do
      ([a]
bs, MSF m () [a]
msf'') <- forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m () [a]
msf' ()
      MSF m () [a] -> [a] -> m (a, MSF m a a)
tick MSF m () [a]
msf'' [a]
bs