module Data.Stream.Except where

-- base
import Control.Monad (ap)
import Data.Void

-- transformers
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except

-- mmorph
import Control.Monad.Morph (MFunctor, hoist)

-- selective
import Control.Selective

-- automaton
import Data.Stream (foreverExcept)
import Data.Stream.Optimized (OptimizedStreamT, applyExcept, constM, selectExcept)
import Data.Stream.Optimized qualified as StreamOptimized
import Data.Stream.Recursive (Recursive (..))
import Data.Stream.Recursive.Except

{- | A stream that can terminate with an exception.

In @automaton@, such streams mainly serve as a vehicle to bring control flow to 'Data.Automaton.Trans.Except.AutomatonExcept'
(which is based on 'StreamExcept'), and the docs there apply here as well.

'StreamExcept' is not only a 'Monad', it also has more efficient 'Selective', 'Applicative', and 'Functor' interfaces.
-}
data StreamExcept a m e
  = -- | When using '>>=', this encoding will be used.
    RecursiveExcept (Recursive (ExceptT e m) a)
  | -- | This is usually the faster encoding, as it can be optimized by GHC.
    CoalgebraicExcept (OptimizedStreamT (ExceptT e m) a)

-- | Apply a function to the output of the stream
mapOutput :: (Functor m) => (a -> b) -> StreamExcept a m e -> StreamExcept b m e
mapOutput :: forall (m :: Type -> Type) a b e.
Functor m =>
(a -> b) -> StreamExcept a m e -> StreamExcept b m e
mapOutput a -> b
f (RecursiveExcept Recursive (ExceptT e m) a
final) = Recursive (ExceptT e m) b -> StreamExcept b m e
forall a (m :: Type -> Type) e.
Recursive (ExceptT e m) a -> StreamExcept a m e
RecursiveExcept (Recursive (ExceptT e m) b -> StreamExcept b m e)
-> Recursive (ExceptT e m) b -> StreamExcept b m e
forall a b. (a -> b) -> a -> b
$ a -> b
f (a -> b) -> Recursive (ExceptT e m) a -> Recursive (ExceptT e m) b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Recursive (ExceptT e m) a
final
mapOutput a -> b
f (CoalgebraicExcept OptimizedStreamT (ExceptT e m) a
initial) = OptimizedStreamT (ExceptT e m) b -> StreamExcept b m e
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT e m) b -> StreamExcept b m e)
-> OptimizedStreamT (ExceptT e m) b -> StreamExcept b m e
forall a b. (a -> b) -> a -> b
$ a -> b
f (a -> b)
-> OptimizedStreamT (ExceptT e m) a
-> OptimizedStreamT (ExceptT e m) b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> OptimizedStreamT (ExceptT e m) a
initial

toRecursive :: (Functor m) => StreamExcept a m e -> Recursive (ExceptT e m) a
toRecursive :: forall (m :: Type -> Type) a e.
Functor m =>
StreamExcept a m e -> Recursive (ExceptT e m) a
toRecursive (RecursiveExcept Recursive (ExceptT e m) a
coalgebraic) = Recursive (ExceptT e m) a
coalgebraic
toRecursive (CoalgebraicExcept OptimizedStreamT (ExceptT e m) a
coalgebraic) = OptimizedStreamT (ExceptT e m) a -> Recursive (ExceptT e m) a
forall (m :: Type -> Type) a.
Functor m =>
OptimizedStreamT m a -> Recursive m a
StreamOptimized.toRecursive OptimizedStreamT (ExceptT e m) a
coalgebraic

runStreamExcept :: StreamExcept a m e -> OptimizedStreamT (ExceptT e m) a
runStreamExcept :: forall a (m :: Type -> Type) e.
StreamExcept a m e -> OptimizedStreamT (ExceptT e m) a
runStreamExcept (RecursiveExcept Recursive (ExceptT e m) a
coalgebraic) = Recursive (ExceptT e m) a -> OptimizedStreamT (ExceptT e m) a
forall (m :: Type -> Type) a. Recursive m a -> OptimizedStreamT m a
StreamOptimized.fromRecursive Recursive (ExceptT e m) a
coalgebraic
runStreamExcept (CoalgebraicExcept OptimizedStreamT (ExceptT e m) a
coalgebraic) = OptimizedStreamT (ExceptT e m) a
coalgebraic

instance (Monad m) => Functor (StreamExcept a m) where
  fmap :: forall a b. (a -> b) -> StreamExcept a m a -> StreamExcept a m b
fmap a -> b
f (RecursiveExcept Recursive (ExceptT a m) a
fe) = Recursive (ExceptT b m) a -> StreamExcept a m b
forall a (m :: Type -> Type) e.
Recursive (ExceptT e m) a -> StreamExcept a m e
RecursiveExcept (Recursive (ExceptT b m) a -> StreamExcept a m b)
-> Recursive (ExceptT b m) a -> StreamExcept a m b
forall a b. (a -> b) -> a -> b
$ (forall a. ExceptT a m a -> ExceptT b m a)
-> Recursive (ExceptT a m) a -> Recursive (ExceptT b m) a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a) -> Recursive m b -> Recursive n b
hoist ((a -> b) -> ExceptT a m a -> ExceptT b m a
forall (m :: Type -> Type) e e' a.
Functor m =>
(e -> e') -> ExceptT e m a -> ExceptT e' m a
withExceptT a -> b
f) Recursive (ExceptT a m) a
fe
  fmap a -> b
f (CoalgebraicExcept OptimizedStreamT (ExceptT a m) a
ae) = OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b)
-> OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a b. (a -> b) -> a -> b
$ (forall a. ExceptT a m a -> ExceptT b m a)
-> OptimizedStreamT (ExceptT a m) a
-> OptimizedStreamT (ExceptT b m) a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a)
-> OptimizedStreamT m b -> OptimizedStreamT n b
hoist ((a -> b) -> ExceptT a m a -> ExceptT b m a
forall (m :: Type -> Type) e e' a.
Functor m =>
(e -> e') -> ExceptT e m a -> ExceptT e' m a
withExceptT a -> b
f) OptimizedStreamT (ExceptT a m) a
ae

instance (Monad m) => Applicative (StreamExcept a m) where
  pure :: forall a. a -> StreamExcept a m a
pure = OptimizedStreamT (ExceptT a m) a -> StreamExcept a m a
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT a m) a -> StreamExcept a m a)
-> (a -> OptimizedStreamT (ExceptT a m) a)
-> a
-> StreamExcept a m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExceptT a m a -> OptimizedStreamT (ExceptT a m) a
forall (m :: Type -> Type) a. m a -> OptimizedStreamT m a
constM (ExceptT a m a -> OptimizedStreamT (ExceptT a m) a)
-> (a -> ExceptT a m a) -> a -> OptimizedStreamT (ExceptT a m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ExceptT a m a
forall (m :: Type -> Type) e a. Monad m => e -> ExceptT e m a
throwE
  CoalgebraicExcept OptimizedStreamT (ExceptT (a -> b) m) a
f <*> :: forall a b.
StreamExcept a m (a -> b)
-> StreamExcept a m a -> StreamExcept a m b
<*> CoalgebraicExcept OptimizedStreamT (ExceptT a m) a
a = OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b)
-> OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a b. (a -> b) -> a -> b
$ OptimizedStreamT (ExceptT (a -> b) m) a
-> OptimizedStreamT (ExceptT a m) a
-> OptimizedStreamT (ExceptT b m) a
forall (m :: Type -> Type) e1 e2 a.
Monad m =>
OptimizedStreamT (ExceptT (e1 -> e2) m) a
-> OptimizedStreamT (ExceptT e1 m) a
-> OptimizedStreamT (ExceptT e2 m) a
applyExcept OptimizedStreamT (ExceptT (a -> b) m) a
f OptimizedStreamT (ExceptT a m) a
a
  StreamExcept a m (a -> b)
f <*> StreamExcept a m a
a = StreamExcept a m (a -> b)
-> StreamExcept a m a -> StreamExcept a m b
forall (m :: Type -> Type) a b. Monad m => m (a -> b) -> m a -> m b
ap StreamExcept a m (a -> b)
f StreamExcept a m a
a

instance (Monad m) => Selective (StreamExcept a m) where
  select :: forall a b.
StreamExcept a m (Either a b)
-> StreamExcept a m (a -> b) -> StreamExcept a m b
select (CoalgebraicExcept OptimizedStreamT (ExceptT (Either a b) m) a
e) (CoalgebraicExcept OptimizedStreamT (ExceptT (a -> b) m) a
f) = OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b)
-> OptimizedStreamT (ExceptT b m) a -> StreamExcept a m b
forall a b. (a -> b) -> a -> b
$ OptimizedStreamT (ExceptT (Either a b) m) a
-> OptimizedStreamT (ExceptT (a -> b) m) a
-> OptimizedStreamT (ExceptT b m) a
forall (m :: Type -> Type) e1 e2 a.
Monad m =>
OptimizedStreamT (ExceptT (Either e1 e2) m) a
-> OptimizedStreamT (ExceptT (e1 -> e2) m) a
-> OptimizedStreamT (ExceptT e2 m) a
selectExcept OptimizedStreamT (ExceptT (Either a b) m) a
e OptimizedStreamT (ExceptT (a -> b) m) a
f
  select StreamExcept a m (Either a b)
e StreamExcept a m (a -> b)
f = StreamExcept a m (Either a b)
-> StreamExcept a m (a -> b) -> StreamExcept a m b
forall (f :: Type -> Type) a b.
Monad f =>
f (Either a b) -> f (a -> b) -> f b
selectM StreamExcept a m (Either a b)
e StreamExcept a m (a -> b)
f

-- | 'return'/'pure' throw exceptions, '(>>=)' uses the last thrown exception as input for an exception handler.
instance (Monad m) => Monad (StreamExcept a m) where
  >> :: forall a b.
StreamExcept a m a -> StreamExcept a m b -> StreamExcept a m b
(>>) = StreamExcept a m a -> StreamExcept a m b -> StreamExcept a m b
forall a b.
StreamExcept a m a -> StreamExcept a m b -> StreamExcept a m b
forall (f :: Type -> Type) a b. Applicative f => f a -> f b -> f b
(*>)
  StreamExcept a m a
ae >>= :: forall a b.
StreamExcept a m a
-> (a -> StreamExcept a m b) -> StreamExcept a m b
>>= a -> StreamExcept a m b
f = Recursive (ExceptT b m) a -> StreamExcept a m b
forall a (m :: Type -> Type) e.
Recursive (ExceptT e m) a -> StreamExcept a m e
RecursiveExcept (Recursive (ExceptT b m) a -> StreamExcept a m b)
-> Recursive (ExceptT b m) a -> StreamExcept a m b
forall a b. (a -> b) -> a -> b
$ Recursive (ExceptT a m) a
-> (a -> Recursive (ExceptT b m) a) -> Recursive (ExceptT b m) a
forall (m :: Type -> Type) e1 b e2.
Monad m =>
Recursive (ExceptT e1 m) b
-> (e1 -> Recursive (ExceptT e2 m) b) -> Recursive (ExceptT e2 m) b
handleExceptT (StreamExcept a m a -> Recursive (ExceptT a m) a
forall (m :: Type -> Type) a e.
Functor m =>
StreamExcept a m e -> Recursive (ExceptT e m) a
toRecursive StreamExcept a m a
ae) (StreamExcept a m b -> Recursive (ExceptT b m) a
forall (m :: Type -> Type) a e.
Functor m =>
StreamExcept a m e -> Recursive (ExceptT e m) a
toRecursive (StreamExcept a m b -> Recursive (ExceptT b m) a)
-> (a -> StreamExcept a m b) -> a -> Recursive (ExceptT b m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> StreamExcept a m b
f)

instance MonadTrans (StreamExcept a) where
  lift :: forall (m :: Type -> Type) a. Monad m => m a -> StreamExcept a m a
lift = OptimizedStreamT (ExceptT a m) a -> StreamExcept a m a
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT a m) a -> StreamExcept a m a)
-> (m a -> OptimizedStreamT (ExceptT a m) a)
-> m a
-> StreamExcept a m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExceptT a m a -> OptimizedStreamT (ExceptT a m) a
forall (m :: Type -> Type) a. m a -> OptimizedStreamT m a
constM (ExceptT a m a -> OptimizedStreamT (ExceptT a m) a)
-> (m a -> ExceptT a m a)
-> m a
-> OptimizedStreamT (ExceptT a m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m (Either a a) -> ExceptT a m a
forall e (m :: Type -> Type) a. m (Either e a) -> ExceptT e m a
ExceptT (m (Either a a) -> ExceptT a m a)
-> (m a -> m (Either a a)) -> m a -> ExceptT a m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Either a a) -> m a -> m (Either a a)
forall a b. (a -> b) -> m a -> m b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Either a a
forall a b. a -> Either a b
Left

instance MFunctor (StreamExcept a) where
  hoist :: forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a) -> StreamExcept a m b -> StreamExcept a n b
hoist forall a. m a -> n a
morph (RecursiveExcept Recursive (ExceptT b m) a
recursive) = Recursive (ExceptT b n) a -> StreamExcept a n b
forall a (m :: Type -> Type) e.
Recursive (ExceptT e m) a -> StreamExcept a m e
RecursiveExcept (Recursive (ExceptT b n) a -> StreamExcept a n b)
-> Recursive (ExceptT b n) a -> StreamExcept a n b
forall a b. (a -> b) -> a -> b
$ (forall a. ExceptT b m a -> ExceptT b n a)
-> Recursive (ExceptT b m) a -> Recursive (ExceptT b n) a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a) -> Recursive m b -> Recursive n b
hoist ((m (Either b a) -> n (Either b a))
-> ExceptT b m a -> ExceptT b n a
forall (m :: Type -> Type) e a (n :: Type -> Type) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT m (Either b a) -> n (Either b a)
forall a. m a -> n a
morph) Recursive (ExceptT b m) a
recursive
  hoist forall a. m a -> n a
morph (CoalgebraicExcept OptimizedStreamT (ExceptT b m) a
coalgebraic) = OptimizedStreamT (ExceptT b n) a -> StreamExcept a n b
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT b n) a -> StreamExcept a n b)
-> OptimizedStreamT (ExceptT b n) a -> StreamExcept a n b
forall a b. (a -> b) -> a -> b
$ (forall a. ExceptT b m a -> ExceptT b n a)
-> OptimizedStreamT (ExceptT b m) a
-> OptimizedStreamT (ExceptT b n) a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a)
-> OptimizedStreamT m b -> OptimizedStreamT n b
hoist ((m (Either b a) -> n (Either b a))
-> ExceptT b m a -> ExceptT b n a
forall (m :: Type -> Type) e a (n :: Type -> Type) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT m (Either b a) -> n (Either b a)
forall a. m a -> n a
morph) OptimizedStreamT (ExceptT b m) a
coalgebraic

safely :: (Monad m) => StreamExcept a m Void -> OptimizedStreamT m a
safely :: forall (m :: Type -> Type) a.
Monad m =>
StreamExcept a m Void -> OptimizedStreamT m a
safely = (forall a. ExceptT Void m a -> m a)
-> OptimizedStreamT (ExceptT Void m) a -> OptimizedStreamT m a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a)
-> OptimizedStreamT m b -> OptimizedStreamT n b
hoist ((Either Void a -> a) -> m (Either Void a) -> m a
forall a b. (a -> b) -> m a -> m b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Void -> a) -> (a -> a) -> Either Void a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Void -> a
forall a. Void -> a
absurd a -> a
forall a. a -> a
id) (m (Either Void a) -> m a)
-> (ExceptT Void m a -> m (Either Void a))
-> ExceptT Void m a
-> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExceptT Void m a -> m (Either Void a)
forall e (m :: Type -> Type) a. ExceptT e m a -> m (Either e a)
runExceptT) (OptimizedStreamT (ExceptT Void m) a -> OptimizedStreamT m a)
-> (StreamExcept a m Void -> OptimizedStreamT (ExceptT Void m) a)
-> StreamExcept a m Void
-> OptimizedStreamT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StreamExcept a m Void -> OptimizedStreamT (ExceptT Void m) a
forall a (m :: Type -> Type) e.
StreamExcept a m e -> OptimizedStreamT (ExceptT e m) a
runStreamExcept

safe :: (Monad m) => OptimizedStreamT m a -> StreamExcept a m void
safe :: forall (m :: Type -> Type) a void.
Monad m =>
OptimizedStreamT m a -> StreamExcept a m void
safe = OptimizedStreamT (ExceptT void m) a -> StreamExcept a m void
forall a (m :: Type -> Type) e.
OptimizedStreamT (ExceptT e m) a -> StreamExcept a m e
CoalgebraicExcept (OptimizedStreamT (ExceptT void m) a -> StreamExcept a m void)
-> (OptimizedStreamT m a -> OptimizedStreamT (ExceptT void m) a)
-> OptimizedStreamT m a
-> StreamExcept a m void
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. m a -> ExceptT void m a)
-> OptimizedStreamT m a -> OptimizedStreamT (ExceptT void m) a
forall {k} (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
       (n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
forall (m :: Type -> Type) (n :: Type -> Type) b.
Monad m =>
(forall a. m a -> n a)
-> OptimizedStreamT m b -> OptimizedStreamT n b
hoist m a -> ExceptT void m a
forall a. m a -> ExceptT void m a
forall (m :: Type -> Type) a. Monad m => m a -> ExceptT void m a
forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

forever :: (Monad m) => StreamExcept a m e -> OptimizedStreamT m a
forever :: forall (m :: Type -> Type) a e.
Monad m =>
StreamExcept a m e -> OptimizedStreamT m a
forever recursive :: StreamExcept a m e
recursive@(RecursiveExcept Recursive (ExceptT e m) a
_) = StreamExcept a m Void -> OptimizedStreamT m a
forall (m :: Type -> Type) a.
Monad m =>
StreamExcept a m Void -> OptimizedStreamT m a
safely StreamExcept a m Void
go
  where
    go :: StreamExcept a m Void
go = StreamExcept a m e
recursive StreamExcept a m e
-> StreamExcept a m Void -> StreamExcept a m Void
forall a b.
StreamExcept a m a -> StreamExcept a m b -> StreamExcept a m b
forall (m :: Type -> Type) a b. Monad m => m a -> m b -> m b
>> StreamExcept a m Void
go
forever (CoalgebraicExcept (StreamOptimized.Stateful StreamT (ExceptT e m) a
stream)) = StreamT m a -> OptimizedStreamT m a
forall (m :: Type -> Type) a. StreamT m a -> OptimizedStreamT m a
StreamOptimized.Stateful (StreamT m a -> OptimizedStreamT m a)
-> StreamT m a -> OptimizedStreamT m a
forall a b. (a -> b) -> a -> b
$ StreamT (ExceptT e m) a -> StreamT m a
forall (m :: Type -> Type) e a.
(Functor m, Monad m) =>
StreamT (ExceptT e m) a -> StreamT m a
foreverExcept StreamT (ExceptT e m) a
stream
forever (CoalgebraicExcept (StreamOptimized.Stateless ExceptT e m a
f)) = m a -> OptimizedStreamT m a
forall (m :: Type -> Type) a. m a -> OptimizedStreamT m a
StreamOptimized.Stateless m a
go
  where
    go :: m a
go = ExceptT e m a -> m (Either e a)
forall e (m :: Type -> Type) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT e m a
f m (Either e a) -> (Either e a -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= (e -> m a) -> (a -> m a) -> Either e a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (m a -> e -> m a
forall a b. a -> b -> a
const m a
go) a -> m a
forall a. a -> m a
forall (m :: Type -> Type) a. Monad m => a -> m a
return