{-# LANGUAGE ViewPatterns, LambdaCase #-}

-- | @do@ blocks for 'CheckedExceptT' that compose exceptions.

--

-- Requires @-fplugin Control.Monad.CheckedExcept.Plugin@ so ambiguous

-- exception-list metavariables (e.g. from 'pure' / 'return' in a block) can

-- default to @'[]@ or a 'Nub' union of accumulated bounds.

module Control.Monad.CheckedExcept.QualifiedDo  ( (>>=)
  , (>>)
  , pure
  , return
  , fail
  ) where

import Control.Monad.CheckedExcept
import Prelude hiding (Monad(..), Applicative(..), MonadFail(..))
import qualified Prelude

type UnionExceptions es1 es2 = Nub (es1 ++ es2)

(>>=) :: forall exceptions1 exceptions2 m a b.
  ( Contains exceptions1 (UnionExceptions exceptions1 exceptions2)
  , Contains exceptions2 (UnionExceptions exceptions1 exceptions2)
  , Prelude.Monad m
  )
  => CheckedExceptT exceptions1 m a
  -> (a -> CheckedExceptT exceptions2 m b)
  -> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
CheckedExceptT exceptions1 m a
m >>= :: forall (exceptions1 :: [*]) (exceptions2 :: [*]) (m :: * -> *) a b.
(Contains exceptions1 (UnionExceptions exceptions1 exceptions2),
 Contains exceptions2 (UnionExceptions exceptions1 exceptions2),
 Monad m) =>
CheckedExceptT exceptions1 m a
-> (a -> CheckedExceptT exceptions2 m b)
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
>>= a -> CheckedExceptT exceptions2 m b
f = do
  m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
forall (exceptions :: [*]) (m :: * -> *) a.
m (Either (OneOf exceptions) a) -> CheckedExceptT exceptions m a
CheckedExceptT (m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
 -> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b)
-> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
forall a b. (a -> b) -> a -> b
$ do
    CheckedExceptT exceptions1 m a -> m (Either (OneOf exceptions1) a)
forall (exceptions :: [*]) (m :: * -> *) a.
CheckedExceptT exceptions m a -> m (Either (OneOf exceptions) a)
runCheckedExceptT CheckedExceptT exceptions1 m a
m m (Either (OneOf exceptions1) a)
-> (Either (OneOf exceptions1) a
    -> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b))
-> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
Prelude.>>= \case
      Left OneOf exceptions1
e ->
        Either (OneOf (UnionExceptions exceptions1 exceptions2)) b
-> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
Prelude.pure (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b
 -> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b))
-> Either (OneOf (UnionExceptions exceptions1 exceptions2)) b
-> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
forall a b. (a -> b) -> a -> b
$
          OneOf (UnionExceptions exceptions1 exceptions2)
-> Either (OneOf (UnionExceptions exceptions1 exceptions2)) b
forall a b. a -> Either a b
Left (forall (exceptions1 :: [*]) (exceptions2 :: [*]).
Contains exceptions1 exceptions2 =>
OneOf exceptions1 -> OneOf exceptions2
weakenOneOf @(exceptions1) @(UnionExceptions exceptions1 exceptions2) OneOf exceptions1
e)
      Right a
a ->
        CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
-> m (Either (OneOf (UnionExceptions exceptions1 exceptions2)) b)
forall (exceptions :: [*]) (m :: * -> *) a.
CheckedExceptT exceptions m a -> m (Either (OneOf exceptions) a)
runCheckedExceptT (forall (exceptions1 :: [*]) (exceptions2 :: [*]) (m :: * -> *) a.
(Functor m, Contains exceptions1 exceptions2) =>
CheckedExceptT exceptions1 m a -> CheckedExceptT exceptions2 m a
weakenExceptions @(exceptions2) @(UnionExceptions exceptions1 exceptions2) (a -> CheckedExceptT exceptions2 m b
f a
a))

-- | Leaves @es@ free; empty 'do' blocks need the type-checker plugin to default

-- @es@ (see module header).

pure :: Prelude.Monad m => a -> CheckedExceptT es m a
pure :: forall (m :: * -> *) a (es :: [*]).
Monad m =>
a -> CheckedExceptT es m a
pure = a -> CheckedExceptT es m a
forall a. a -> CheckedExceptT es m a
forall (f :: * -> *) a. Applicative f => a -> f a
Prelude.pure

-- | Same caveat as 'pure'.

return :: Prelude.Monad m => a -> CheckedExceptT es m a
return :: forall (m :: * -> *) a (es :: [*]).
Monad m =>
a -> CheckedExceptT es m a
return = a -> CheckedExceptT es m a
forall a. a -> CheckedExceptT es m a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return

(>>) :: forall exceptions1 exceptions2 m a x.
  ( Contains exceptions1 (UnionExceptions exceptions1 exceptions2)
  , Contains exceptions2 (UnionExceptions exceptions1 exceptions2)
  , Prelude.Monad m
  )
  => CheckedExceptT exceptions1 m x
  -> CheckedExceptT exceptions2 m a
  -> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m a
CheckedExceptT exceptions1 m x
a >> :: forall (exceptions1 :: [*]) (exceptions2 :: [*]) (m :: * -> *) a x.
(Contains exceptions1 (UnionExceptions exceptions1 exceptions2),
 Contains exceptions2 (UnionExceptions exceptions1 exceptions2),
 Monad m) =>
CheckedExceptT exceptions1 m x
-> CheckedExceptT exceptions2 m a
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m a
>> CheckedExceptT exceptions2 m a
b =
  forall (exceptions1 :: [*]) (exceptions2 :: [*]) (m :: * -> *) a.
(Functor m, Contains exceptions1 exceptions2) =>
CheckedExceptT exceptions1 m a -> CheckedExceptT exceptions2 m a
weakenExceptions @(exceptions1) @(UnionExceptions exceptions1 exceptions2) CheckedExceptT exceptions1 m x
a
    CheckedExceptT (UnionExceptions exceptions1 exceptions2) m x
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m a
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m a
forall a b.
CheckedExceptT (UnionExceptions exceptions1 exceptions2) m a
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
-> CheckedExceptT (UnionExceptions exceptions1 exceptions2) m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
Prelude.>> forall (exceptions1 :: [*]) (exceptions2 :: [*]) (m :: * -> *) a.
(Functor m, Contains exceptions1 exceptions2) =>
CheckedExceptT exceptions1 m a -> CheckedExceptT exceptions2 m a
weakenExceptions @(exceptions2) @(UnionExceptions exceptions1 exceptions2) CheckedExceptT exceptions2 m a
b

fail :: Prelude.MonadFail m => String -> CheckedExceptT es m a
fail :: forall (m :: * -> *) (es :: [*]) a.
MonadFail m =>
String -> CheckedExceptT es m a
fail = String -> CheckedExceptT es m a
forall a. HasCallStack => String -> CheckedExceptT es m a
forall (m :: * -> *) a.
(MonadFail m, HasCallStack) =>
String -> m a
Prelude.fail