{-# LANGUAGE Arrows     #-}
{-# LANGUAGE CPP        #-}
{-# LANGUAGE Rank2Types #-}
-- |
-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- 'MSF's in the 'ExceptT' monad are monadic stream functions that can throw
-- exceptions, i.e. return an exception value instead of a continuation. This
-- module gives ways to throw exceptions in various ways, and to handle them
-- through a monadic interface.
module Control.Monad.Trans.MSF.Except
    ( module Control.Monad.Trans.MSF.Except
    , module Control.Monad.Trans.Except
    )
  where

-- External imports
#if !MIN_VERSION_base(4,8,0)
import           Control.Applicative        (Applicative (..), (<$>))
#endif

import           Control.Arrow              (arr, returnA, (<<<), (>>>))
import qualified Control.Category           as Category
import           Control.Monad              (ap, liftM)
import           Control.Monad.Trans.Class  (lift)
import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen,
                                             liftPass)
import           Control.Monad.Trans.Maybe  (MaybeT, runMaybeT)
import           Data.Void                  (Void)

-- Internal imports
import Data.MonadicStreamFunction              (arrM, constM, count, feedback,
                                                liftTransS, mapMaybeS, morphS,
                                                reactimate)
import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))

-- External, necessary for older base versions
#if !MIN_VERSION_base(4,10,0)
fromLeft  :: a -> Either a b -> a
fromLeft  _ (Left  a) = a
fromLeft  a (Right _) = a
fromRight :: b -> Either a b -> b
fromRight _ (Right b) = b
fromRight b (Left  _) = b
#else
import           Data.Either                (fromLeft, fromRight)
#endif

-- * Throwing exceptions

-- | Throw the exception 'e' whenever the function evaluates to 'True'.
throwOnCond :: Monad m => (a -> Bool) -> e -> MSF (ExceptT e m) a a
throwOnCond :: forall (m :: * -> *) a e.
Monad m =>
(a -> Bool) -> e -> MSF (ExceptT e m) a a
throwOnCond a -> Bool
cond e
e = proc a
a -> if a -> Bool
cond a
a
  then forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS  -< e
e
  else forall (a :: * -> * -> *) b. Arrow a => a b b
returnA -< a
a

-- | Throws the exception when the input is 'True'. Variant of 'throwOnCond'
-- for Kleisli arrows.
throwOnCondM :: Monad m => (a -> m Bool) -> e -> MSF (ExceptT e m) a a
throwOnCondM :: forall (m :: * -> *) a e.
Monad m =>
(a -> m Bool) -> e -> MSF (ExceptT e m) a a
throwOnCondM a -> m Bool
cond e
e = proc a
a -> do
  Bool
b <- forall (m :: * -> *) a b. Monad m => (a -> m b) -> MSF m a b
arrM (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m Bool
cond) -< a
a
  if Bool
b
    then forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS  -< e
e
    else forall (a :: * -> * -> *) b. Arrow a => a b b
returnA -< a
a

-- | Throw the exception when the input is 'True'.
throwOn :: Monad m => e -> MSF (ExceptT e m) Bool ()
throwOn :: forall (m :: * -> *) e. Monad m => e -> MSF (ExceptT e m) Bool ()
throwOn e
e = proc Bool
b -> forall (m :: * -> *) e. Monad m => MSF (ExceptT e m) (Bool, e) ()
throwOn' -< (Bool
b, e
e)

-- | Variant of 'throwOn', where the exception may change every tick.
throwOn' :: Monad m => MSF (ExceptT e m) (Bool, e) ()
throwOn' :: forall (m :: * -> *) e. Monad m => MSF (ExceptT e m) (Bool, e) ()
throwOn' = proc (Bool
b, e
e) -> if Bool
b
  then forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS  -< e
e
  else forall (a :: * -> * -> *) b. Arrow a => a b b
returnA -< ()

-- | When the input is @Just e@, throw the exception @e@. (Does not output any
-- actual data.)
throwMaybe :: Monad m => MSF (ExceptT e m) (Maybe e) (Maybe a)
throwMaybe :: forall (m :: * -> *) e a.
Monad m =>
MSF (ExceptT e m) (Maybe e) (Maybe a)
throwMaybe = forall (m :: * -> *) a b.
Monad m =>
MSF m a b -> MSF m (Maybe a) (Maybe b)
mapMaybeS forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS

-- | Immediately throw the incoming exception.
throwS :: Monad m => MSF (ExceptT e m) e a
throwS :: forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS = forall (m :: * -> *) a b. Monad m => (a -> m b) -> MSF m a b
arrM forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE

-- | Immediately throw the given exception.
throw :: Monad m => e -> MSF (ExceptT e m) a b
throw :: forall (m :: * -> *) e a b. Monad m => e -> MSF (ExceptT e m) a b
throw = forall (m :: * -> *) b a. Monad m => m b -> MSF m a b
constM forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE

-- | Do not throw an exception.
pass :: Monad m => MSF (ExceptT e m) a a
pass :: forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) a a
pass = forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
Category.id

-- | Converts an 'MSF' in 'MaybeT' to an 'MSF' in 'ExceptT'. Whenever
-- 'Nothing' is thrown, throw @()@ instead.
maybeToExceptS :: (Functor m, Monad m)
               => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b
maybeToExceptS :: forall (m :: * -> *) a b.
(Functor m, Monad m) =>
MSF (MaybeT m) a b -> MSF (ExceptT () m) a b
maybeToExceptS = forall (m2 :: * -> *) (m1 :: * -> *) a b.
(Monad m2, Monad m1) =>
(forall c. m1 c -> m2 c) -> MSF m1 a b -> MSF m2 a b
morphS (forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a b. a -> Either a b
Left ()) forall a b. b -> Either a b
Right forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT)

-- * Catching exceptions

-- | Catch an exception in an 'MSF'. As soon as an exception occurs, the
-- current continuation is replaced by a new 'MSF', the exception handler,
-- based on the exception value. For exception catching where the handler can
-- throw further exceptions, see 'MSFExcept' further below.
catchS :: Monad m => MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b
catchS :: forall (m :: * -> *) e a b.
Monad m =>
MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b
catchS MSF (ExceptT e m) a b
msf e -> MSF m a b
f = forall (m :: * -> *) a b.
Monad m =>
MSFExcept m a b Void -> MSF m a b
safely forall a b. (a -> b) -> a -> b
$ do
  e
e <- forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try MSF (ExceptT e m) a b
msf
  forall (m :: * -> *) a b e.
Monad m =>
MSF m a b -> MSFExcept m a b e
safe forall a b. (a -> b) -> a -> b
$ e -> MSF m a b
f e
e

-- | Similar to Yampa's delayed switching. Loses a @b@ in case of an exception.
untilE :: Monad m
       => MSF m a b
       -> MSF m b (Maybe e)
       -> MSF (ExceptT e m) a b
untilE :: forall (m :: * -> *) a b e.
Monad m =>
MSF m a b -> MSF m b (Maybe e) -> MSF (ExceptT e m) a b
untilE MSF m a b
msf MSF m b (Maybe e)
msfe = proc a
a -> do
  b
b  <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS MSF m a b
msf  -< a
a
  Maybe e
me <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS MSF m b (Maybe e)
msfe -< b
b
  forall (m :: * -> *) e a.
Monad m =>
MSF (ExceptT e m) (ExceptT e m a) a
inExceptT -< forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a b. b -> Either a b
Right b
b) forall a b. a -> Either a b
Left Maybe e
me

-- | Escape an 'ExceptT' layer by outputting the exception whenever it occurs.
-- If an exception occurs, the current 'MSF' continuation is tested again on
-- the next input.
exceptS :: (Functor m, Monad m) => MSF (ExceptT e m) a b -> MSF m a (Either e b)
exceptS :: forall (m :: * -> *) e a b.
(Functor m, Monad m) =>
MSF (ExceptT e m) a b -> MSF m a (Either e b)
exceptS = forall (m1 :: * -> *) (m2 :: * -> *) a2 a1 b1 b2.
(Monad m1, Monad m2) =>
(a2 -> m1 a1)
-> (forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c))
-> MSF m1 a1 b1
-> MSF m2 a2 b2
transG forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall {a} {b} {a}. Either a (b, a) -> (Either a b, Maybe a)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT
  where
    f :: Either a (b, a) -> (Either a b, Maybe a)
f (Left a
e)       = (forall a b. a -> Either a b
Left a
e , forall a. Maybe a
Nothing)
    f (Right (b
b, a
c)) = (forall a b. b -> Either a b
Right b
b, forall a. a -> Maybe a
Just a
c )

-- | Embed an 'ExceptT' value inside the 'MSF'. Whenever the input value is an
-- ordinary value, it is passed on. If it is an exception, it is raised.
inExceptT :: Monad m => MSF (ExceptT e m) (ExceptT e m a) a
inExceptT :: forall (m :: * -> *) e a.
Monad m =>
MSF (ExceptT e m) (ExceptT e m a) a
inExceptT = forall (m :: * -> *) a b. Monad m => (a -> m b) -> MSF m a b
arrM forall a. a -> a
id

-- | In case an exception occurs in the first argument, replace the exception
-- by the second component of the tuple.
tagged :: Monad m => MSF (ExceptT e1 m) a b -> MSF (ExceptT e2 m) (a, e2) b
tagged :: forall (m :: * -> *) e1 a b e2.
Monad m =>
MSF (ExceptT e1 m) a b -> MSF (ExceptT e2 m) (a, e2) b
tagged MSF (ExceptT e1 m) a b
msf = forall (m :: * -> *) a b e.
MSFExcept m a b e -> MSF (ExceptT e m) a b
runMSFExcept forall a b. (a -> b) -> a -> b
$ do
  e1
_       <- forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall a b. (a -> b) -> a -> b
$ MSF (ExceptT e1 m) a b
msf forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
<<< forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr forall a b. (a, b) -> a
fst
  (a
_, e2
e2) <- forall (m :: * -> *) e b. Monad m => MSFExcept m e b e
currentInput
  forall (m :: * -> *) a. Monad m => a -> m a
return e2
e2

-- * Monad interface for Exception MSFs

-- | 'MSF's with an 'ExceptT' transformer layer are in fact monads /in the
-- exception type/.
--
--   * 'return' corresponds to throwing an exception immediately.
--   * '>>=' is exception handling: The first value throws an exception, while
--     the Kleisli arrow handles the exception and produces a new signal
--     function, which can throw exceptions in a different type.
--   * @m@: The monad that the 'MSF' may take side effects in.
--   * @a@: The input type
--   * @b@: The output type
--   * @e@: The type of exceptions that can be thrown
newtype MSFExcept m a b e = MSFExcept { forall (m :: * -> *) a b e.
MSFExcept m a b e -> MSF (ExceptT e m) a b
runMSFExcept :: MSF (ExceptT e m) a b }

-- | Execute an 'MSF' in 'ExceptT' until it raises an exception.
--
-- An alias for the 'MSFExcept' constructor, used to enter the 'MSFExcept'
-- monad context.
try :: MSF (ExceptT e m) a b -> MSFExcept m a b e
try :: forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try = forall (m :: * -> *) a b e.
MSF (ExceptT e m) a b -> MSFExcept m a b e
MSFExcept

-- | Immediately throw the current input as an exception.
currentInput :: Monad m => MSFExcept m e b e
currentInput :: forall (m :: * -> *) e b. Monad m => MSFExcept m e b e
currentInput = forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS

-- | Functor instance for MSFs on the 'Either' monad. Fmapping is the same as
-- applying a transformation to the 'Left' values.
instance Monad m => Functor (MSFExcept m a b) where
  fmap :: forall a b. (a -> b) -> MSFExcept m a b a -> MSFExcept m a b b
fmap = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM

-- | Applicative instance for MSFs on the 'Either' monad. The function 'pure'
-- throws an exception.
instance Monad m => Applicative (MSFExcept m a b) where
  pure :: forall a. a -> MSFExcept m a b a
pure = forall (m :: * -> *) a b e.
MSF (ExceptT e m) a b -> MSFExcept m a b e
MSFExcept forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) e a b. Monad m => e -> MSF (ExceptT e m) a b
throw
  <*> :: forall a b.
MSFExcept m a b (a -> b) -> MSFExcept m a b a -> MSFExcept m a b b
(<*>) = forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap

-- | Monad instance for 'MSFExcept'. Bind uses the exception as the 'return'
-- value in the monad.
instance Monad m => Monad (MSFExcept m a b) where
  return :: forall a. a -> MSFExcept m a b a
return = forall (f :: * -> *) a. Applicative f => a -> f a
pure
  MSFExcept MSF (ExceptT a m) a b
msf >>= :: forall a b.
MSFExcept m a b a -> (a -> MSFExcept m a b b) -> MSFExcept m a b b
>>= a -> MSFExcept m a b b
f = forall (m :: * -> *) a b e.
MSF (ExceptT e m) a b -> MSFExcept m a b e
MSFExcept forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e1 a b e2.
Monad m =>
MSF (ExceptT e1 m) a b
-> (e1 -> MSF (ExceptT e2 m) a b) -> MSF (ExceptT e2 m) a b
handleExceptT MSF (ExceptT a m) a b
msf forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b e.
MSFExcept m a b e -> MSF (ExceptT e m) a b
runMSFExcept forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> MSFExcept m a b b
f

-- | Execute an MSF and, if it throws an exception, recover by switching to a
-- second MSF.
handleExceptT :: Monad m
              => MSF (ExceptT e1 m) a b
              -> (e1 -> MSF (ExceptT e2 m) a b)
              -> MSF (ExceptT e2 m) a b
handleExceptT :: forall (m :: * -> *) e1 a b e2.
Monad m =>
MSF (ExceptT e1 m) a b
-> (e1 -> MSF (ExceptT e2 m) a b) -> MSF (ExceptT e2 m) a b
handleExceptT MSF (ExceptT e1 m) a b
msf e1 -> MSF (ExceptT e2 m) a b
f = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a (m1 :: * -> *) b1 (m2 :: * -> *) b2.
(a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2))
-> MSF m1 a b1 -> MSF m2 a b2
handleGen MSF (ExceptT e1 m) a b
msf forall a b. (a -> b) -> a -> b
$ \a
a ExceptT e1 m (b, MSF (ExceptT e1 m) a b)
mbcont -> do
  Either e1 (b, MSF (ExceptT e1 m) a b)
ebcont <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT e1 m (b, MSF (ExceptT e1 m) a b)
mbcont
  case Either e1 (b, MSF (ExceptT e1 m) a b)
ebcont of
    Left e1
e          -> forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF (e1 -> MSF (ExceptT e2 m) a b
f e1
e) a
a
    Right (b
b, MSF (ExceptT e1 m) a b
msf') -> forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, forall (m :: * -> *) e1 a b e2.
Monad m =>
MSF (ExceptT e1 m) a b
-> (e1 -> MSF (ExceptT e2 m) a b) -> MSF (ExceptT e2 m) a b
handleExceptT MSF (ExceptT e1 m) a b
msf' e1 -> MSF (ExceptT e2 m) a b
f)

-- | If no exception can occur, the 'MSF' can be executed without the 'ExceptT'
-- layer.
safely :: Monad m => MSFExcept m a b Void -> MSF m a b
safely :: forall (m :: * -> *) a b.
Monad m =>
MSFExcept m a b Void -> MSF m a b
safely (MSFExcept MSF (ExceptT Void m) a b
msf) = forall (m2 :: * -> *) (m1 :: * -> *) a b.
(Monad m2, Monad m1) =>
(forall c. m1 c -> m2 c) -> MSF m1 a b -> MSF m2 a b
morphS forall {m :: * -> *} {a} {b}. Monad m => ExceptT a m b -> m b
fromExcept MSF (ExceptT Void m) a b
msf
  where
    -- We can assume that the pattern @Left e@ will not occur, since @e@ would
    -- have to be of type @Void@.
    fromExcept :: ExceptT a m b -> m b
fromExcept ExceptT a m b
ma = do
      Either a b
rightMa <- forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT a m b
ma
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall b a. b -> Either a b -> b
fromRight (forall a. HasCallStack => [Char] -> a
error [Char]
"safely: Received `Left`") Either a b
rightMa

-- | An 'MSF' without an 'ExceptT' layer never throws an exception, and can
-- thus have an arbitrary exception type.
safe :: Monad m => MSF m a b -> MSFExcept m a b e
safe :: forall (m :: * -> *) a b e.
Monad m =>
MSF m a b -> MSFExcept m a b e
safe = forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS

-- | Inside the 'MSFExcept' monad, execute an action of the wrapped monad.
-- This passes the last input value to the action, but doesn't advance a tick.
once :: Monad m => (a -> m e) -> MSFExcept m a b e
once :: forall (m :: * -> *) a e b.
Monad m =>
(a -> m e) -> MSFExcept m a b e
once a -> m e
f = forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b. Monad m => (a -> m b) -> MSF m a b
arrM (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m e
f) forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall (m :: * -> *) e a. Monad m => MSF (ExceptT e m) e a
throwS

-- | Variant of 'once' without input.
once_ :: Monad m => m e -> MSFExcept m a b e
once_ :: forall (m :: * -> *) e a b. Monad m => m e -> MSFExcept m a b e
once_ = forall (m :: * -> *) a e b.
Monad m =>
(a -> m e) -> MSFExcept m a b e
once forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const

-- | Advances a single tick with the given Kleisli arrow, and then throws an
-- exception.
step :: Monad m => (a -> m (b, e)) -> MSFExcept m a b e
step :: forall (m :: * -> *) a b e.
Monad m =>
(a -> m (b, e)) -> MSFExcept m a b e
step a -> m (b, e)
f = forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall a b. (a -> b) -> a -> b
$ proc a
a -> do
  Int
n      <- forall n (m :: * -> *) a. (Num n, Monad m) => MSF m a n
count           -< ()
  (b
b, e
e) <- forall (m :: * -> *) a b. Monad m => (a -> m b) -> MSF m a b
arrM (forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m (b, e)
f) -< a
a
  ()
_      <- forall (m :: * -> *) e. Monad m => MSF (ExceptT e m) (Bool, e) ()
throwOn'        -< (Int
n forall a. Ord a => a -> a -> Bool
> (Int
1 :: Int), e
e)
  forall (a :: * -> * -> *) b. Arrow a => a b b
returnA                   -< b
b

-- | Advances a single tick outputting the value, and then throws '()'.
step_ :: Monad m => b -> MSFExcept m a b ()
step_ :: forall (m :: * -> *) b a. Monad m => b -> MSFExcept m a b ()
step_ b
b = forall (m :: * -> *) a b e.
Monad m =>
(a -> m (b, e)) -> MSFExcept m a b e
step forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, ())

-- | Converts a list to an 'MSFExcept', which outputs an element of the list at
-- each step, throwing '()' when the list ends.
listToMSFExcept :: Monad m => [b] -> MSFExcept m a b ()
listToMSFExcept :: forall (m :: * -> *) b a. Monad m => [b] -> MSFExcept m a b ()
listToMSFExcept = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ forall (m :: * -> *) b a. Monad m => b -> MSFExcept m a b ()
step_

-- * Utilities definable in terms of 'MSFExcept'

-- | Extract an 'MSF' from a monadic action.
--
-- Runs a monadic action that produces an 'MSF' on the first iteration/step,
-- and uses that 'MSF' as the main signal function for all inputs (including
-- the first one).
performOnFirstSample :: Monad m => m (MSF m a b) -> MSF m a b
performOnFirstSample :: forall (m :: * -> *) a b. Monad m => m (MSF m a b) -> MSF m a b
performOnFirstSample m (MSF m a b)
sfaction = forall (m :: * -> *) a b.
Monad m =>
MSFExcept m a b Void -> MSF m a b
safely forall a b. (a -> b) -> a -> b
$ do
  MSF m a b
msf <- forall (m :: * -> *) e a b. Monad m => m e -> MSFExcept m a b e
once_ m (MSF m a b)
sfaction
  forall (m :: * -> *) a b e.
Monad m =>
MSF m a b -> MSFExcept m a b e
safe MSF m a b
msf

-- | Reactimates an 'MSFExcept' until it throws an exception.
reactimateExcept :: Monad m => MSFExcept m () () e -> m e
reactimateExcept :: forall (m :: * -> *) e. Monad m => MSFExcept m () () e -> m e
reactimateExcept MSFExcept m () () e
msfe = do
  Either e ()
leftMe <- forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). Monad m => MSF m () () -> m ()
reactimate forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b e.
MSFExcept m a b e -> MSF (ExceptT e m) a b
runMSFExcept MSFExcept m () () e
msfe
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b -> a
fromLeft (forall a. HasCallStack => [Char] -> a
error [Char]
"reactimateExcept: Received `Right`") Either e ()
leftMe

-- | Reactimates an 'MSF' until it returns 'True'.
reactimateB :: Monad m => MSF m () Bool -> m ()
reactimateB :: forall (m :: * -> *). Monad m => MSF m () Bool -> m ()
reactimateB MSF m () Bool
sf = forall (m :: * -> *) e. Monad m => MSFExcept m () () e -> m e
reactimateExcept forall a b. (a -> b) -> a -> b
$ forall e (m :: * -> *) a b.
MSF (ExceptT e m) a b -> MSFExcept m a b e
try forall a b. (a -> b) -> a -> b
$ forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS MSF m () Bool
sf forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall (m :: * -> *) e. Monad m => e -> MSF (ExceptT e m) Bool ()
throwOn ()

-- | Run first MSF until the second value in the output tuple is @Just c@ (for
-- some @c@), then start the second MSF.
--
-- Analog to Yampa's
-- [@switch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:switch),
-- with 'Maybe' instead of @Event@.
switch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
switch :: forall (m :: * -> *) a b c.
Monad m =>
MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
switch MSF m a (b, Maybe c)
sf c -> MSF m a b
f = forall (m :: * -> *) e a b.
Monad m =>
MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b
catchS MSF (ExceptT c m) a b
ef c -> MSF m a b
f
  where
    -- Run sf, throwing an exception if there is a no-Nothing value in the
    -- second element of the pair, and returning the first element otherwise.
    ef :: MSF (ExceptT c m) a b
ef = proc a
a -> do
           (b
b, Maybe c
me)  <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS MSF m a (b, Maybe c)
sf  -< a
a
           forall (m :: * -> *) e a.
Monad m =>
MSF (ExceptT e m) (Maybe e) (Maybe a)
throwMaybe                 -< Maybe c
me
           forall (a :: * -> * -> *) b. Arrow a => a b b
returnA                    -< b
b

-- | Run first MSF until the second value in the output tuple is @Just c@ (for
-- some @c@), then start the second MSF.
--
-- Analog to Yampa's
-- [@dswitch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:dSwitch),
-- with 'Maybe' instead of @Event@.
dSwitch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
dSwitch :: forall (m :: * -> *) a b c.
Monad m =>
MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b
dSwitch MSF m a (b, Maybe c)
sf c -> MSF m a b
f = forall (m :: * -> *) e a b.
Monad m =>
MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b
catchS MSF (ExceptT c m) a b
ef c -> MSF m a b
f
  where
    ef :: MSF (ExceptT c m) a b
ef = forall (m :: * -> *) c a b.
Monad m =>
c -> MSF m (a, c) (b, c) -> MSF m a b
feedback forall a. Maybe a
Nothing forall a b. (a -> b) -> a -> b
$ proc (a
a, Maybe c
me) -> do
           forall (m :: * -> *) e a.
Monad m =>
MSF (ExceptT e m) (Maybe e) (Maybe a)
throwMaybe    -< Maybe c
me
           forall (t :: (* -> *) -> * -> *) (m :: * -> *) a b.
(MonadTrans t, Monad m, Monad (t m)) =>
MSF m a b -> MSF (t m) a b
liftTransS MSF m a (b, Maybe c)
sf -< a
a

-- | More general lifting combinator that enables recovery. Note that, unlike a
-- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary
-- function needs to be a bit more structured, and produces a Maybe value. The
-- previous 'MSF' is used if a new one is not produced.
transG :: (Monad m1, Monad m2)
       => (a2 -> m1 a1)
       -> (forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c))
       -> MSF m1 a1 b1
       -> MSF m2 a2 b2
transG :: forall (m1 :: * -> *) (m2 :: * -> *) a2 a1 b1 b2.
(Monad m1, Monad m2) =>
(a2 -> m1 a1)
-> (forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c))
-> MSF m1 a1 b1
-> MSF m2 a2 b2
transG a2 -> m1 a1
transformInput forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c)
transformOutput MSF m1 a1 b1
msf = MSF m2 a2 b2
go
  where
    go :: MSF m2 a2 b2
go = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \a2
a2 -> do
           (b2
b2, Maybe (MSF m1 a1 b1)
msf') <- forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c)
transformOutput a2
a2 forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m1 a1 b1
msf forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< a2 -> m1 a1
transformInput a2
a2
           case Maybe (MSF m1 a1 b1)
msf' of
             Just MSF m1 a1 b1
msf'' ->
               forall (m :: * -> *) a. Monad m => a -> m a
return (b2
b2, forall (m1 :: * -> *) (m2 :: * -> *) a2 a1 b1 b2.
(Monad m1, Monad m2) =>
(a2 -> m1 a1)
-> (forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c))
-> MSF m1 a1 b1
-> MSF m2 a2 b2
transG a2 -> m1 a1
transformInput forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c)
transformOutput MSF m1 a1 b1
msf'')
             Maybe (MSF m1 a1 b1)
Nothing ->
               forall (m :: * -> *) a. Monad m => a -> m a
return (b2
b2, MSF m2 a2 b2
go)

-- | Use a generic handler to handle exceptions in MSF processing actions.
handleGen :: (a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2))
          -> MSF m1 a b1
          -> MSF m2 a b2
handleGen :: forall a (m1 :: * -> *) b1 (m2 :: * -> *) b2.
(a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2))
-> MSF m1 a b1 -> MSF m2 a b2
handleGen a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2)
handler MSF m1 a b1
msf = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \a
a -> a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2)
handler a
a (forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m1 a b1
msf a
a)