module Data.Stream.Final.Except where

-- transformers
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except (ExceptT, runExceptT)

-- automaton
import Data.Stream.Final (Final (..))
import Data.Stream.Result (mapResultState)

handleExceptT :: (Monad m) => Final (ExceptT e1 m) b -> (e1 -> Final (ExceptT e2 m) b) -> Final (ExceptT e2 m) b
handleExceptT :: forall (m :: Type -> Type) e1 b e2.
Monad m =>
Final (ExceptT e1 m) b
-> (e1 -> Final (ExceptT e2 m) b) -> Final (ExceptT e2 m) b
handleExceptT Final (ExceptT e1 m) b
final e1 -> Final (ExceptT e2 m) b
handler = Final (ExceptT e1 m) b -> Final (ExceptT e2 m) b
go Final (ExceptT e1 m) b
final
  where
    go :: Final (ExceptT e1 m) b -> Final (ExceptT e2 m) b
go Final (ExceptT e1 m) b
final = ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
-> Final (ExceptT e2 m) b
forall (m :: Type -> Type) a. m (Result (Final m a) a) -> Final m a
Final (ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
 -> Final (ExceptT e2 m) b)
-> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
-> Final (ExceptT e2 m) b
forall a b. (a -> b) -> a -> b
$ do
      Either e1 (Result (Final (ExceptT e1 m) b) b)
resultOrException <- m (Either e1 (Result (Final (ExceptT e1 m) b) b))
-> ExceptT e2 m (Either e1 (Result (Final (ExceptT e1 m) b) b))
forall (m :: Type -> Type) a. Monad m => m a -> ExceptT e2 m a
forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Either e1 (Result (Final (ExceptT e1 m) b) b))
 -> ExceptT e2 m (Either e1 (Result (Final (ExceptT e1 m) b) b)))
-> m (Either e1 (Result (Final (ExceptT e1 m) b) b))
-> ExceptT e2 m (Either e1 (Result (Final (ExceptT e1 m) b) b))
forall a b. (a -> b) -> a -> b
$ ExceptT e1 m (Result (Final (ExceptT e1 m) b) b)
-> m (Either e1 (Result (Final (ExceptT e1 m) b) b))
forall e (m :: Type -> Type) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT e1 m (Result (Final (ExceptT e1 m) b) b)
 -> m (Either e1 (Result (Final (ExceptT e1 m) b) b)))
-> ExceptT e1 m (Result (Final (ExceptT e1 m) b) b)
-> m (Either e1 (Result (Final (ExceptT e1 m) b) b))
forall a b. (a -> b) -> a -> b
$ Final (ExceptT e1 m) b
-> ExceptT e1 m (Result (Final (ExceptT e1 m) b) b)
forall (m :: Type -> Type) a. Final m a -> m (Result (Final m a) a)
getFinal Final (ExceptT e1 m) b
final
      case Either e1 (Result (Final (ExceptT e1 m) b) b)
resultOrException of
        Right Result (Final (ExceptT e1 m) b) b
result -> Result (Final (ExceptT e2 m) b) b
-> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
forall a. a -> ExceptT e2 m a
forall (m :: Type -> Type) a. Monad m => a -> m a
return (Result (Final (ExceptT e2 m) b) b
 -> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b))
-> Result (Final (ExceptT e2 m) b) b
-> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
forall a b. (a -> b) -> a -> b
$! (Final (ExceptT e1 m) b -> Final (ExceptT e2 m) b)
-> Result (Final (ExceptT e1 m) b) b
-> Result (Final (ExceptT e2 m) b) b
forall s1 s2 a. (s1 -> s2) -> Result s1 a -> Result s2 a
mapResultState Final (ExceptT e1 m) b -> Final (ExceptT e2 m) b
go Result (Final (ExceptT e1 m) b) b
result
        Left e1
e -> Final (ExceptT e2 m) b
-> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
forall (m :: Type -> Type) a. Final m a -> m (Result (Final m a) a)
getFinal (Final (ExceptT e2 m) b
 -> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b))
-> Final (ExceptT e2 m) b
-> ExceptT e2 m (Result (Final (ExceptT e2 m) b) b)
forall a b. (a -> b) -> a -> b
$ e1 -> Final (ExceptT e2 m) b
handler e1
e