packages feed

servant-checked-exceptions-core 2.1.0.0 → 2.2.0.0

raw patch · 7 files changed

+872/−75 lines, 7 filesdep +contravariantdep +mtldep +transformersdep ~world-peacePVP ok

version bump matches the API change (PVP)

Dependencies added: contravariant, mtl, transformers

Dependency ranges changed: world-peace

API changes (from Hackage documentation)

+ Servant.Checked.Exceptions: EnvelopeT :: m (Envelope es a) -> EnvelopeT es m a
+ Servant.Checked.Exceptions: [runEnvelopeT] :: EnvelopeT es m a -> m (Envelope es a)
+ Servant.Checked.Exceptions: bindEnvT :: (Contains es1 fullEs, Contains es2 fullEs, Monad m) => EnvelopeT es1 m a -> (a -> EnvelopeT es2 m b) -> EnvelopeT fullEs m b
+ Servant.Checked.Exceptions: bindEnvelope :: (Contains es1 fullEs, Contains es2 fullEs) => Envelope es1 a -> (a -> Envelope es2 b) -> Envelope fullEs b
+ Servant.Checked.Exceptions: catchesEnvT :: forall tuple es m a x. (Monad m, ToOpenProduct tuple (ReturnX (m x) es)) => tuple -> (a -> m x) -> EnvelopeT es m a -> m x
+ Servant.Checked.Exceptions: data EnvelopeT es m a
+ Servant.Checked.Exceptions: emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a
+ Servant.Checked.Exceptions: envTRemove :: forall e es m a. (ElemRemove e es, Functor m) => EnvelopeT es m a -> EnvelopeT (Remove e es) m (Either a e)
+ Servant.Checked.Exceptions: envTToExceptT :: Functor m => EnvelopeT es m a -> ExceptT (OpenUnion es) m a
+ Servant.Checked.Exceptions: envelopeHandle :: ElemRemove e es => (Envelope (Remove e es) a -> x) -> (e -> x) -> Envelope es a -> x
+ Servant.Checked.Exceptions: envelopeRemove :: forall e es a. ElemRemove e es => Envelope es a -> Either (Envelope (Remove e es) a) e
+ Servant.Checked.Exceptions: envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c
+ Servant.Checked.Exceptions: errEnvTMatch :: forall e es m a. (Functor m, IsMember e es) => EnvelopeT es m a -> m (Maybe e)
+ Servant.Checked.Exceptions: exceptTToEnvT :: Functor m => ExceptT (OpenUnion es) m a -> EnvelopeT es m a
+ Servant.Checked.Exceptions: fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a
+ Servant.Checked.Exceptions: fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a
+ Servant.Checked.Exceptions: liftA2EnvT :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m) => (a -> b -> c) -> EnvelopeT es1 m a -> EnvelopeT es2 m b -> EnvelopeT fullEs m c
+ Servant.Checked.Exceptions: liftA2Envelope :: (Contains es1 fullEs, Contains es2 fullEs) => (a -> b -> c) -> Envelope es1 a -> Envelope es2 b -> Envelope fullEs c
+ Servant.Checked.Exceptions: pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a
+ Servant.Checked.Exceptions: relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a
+ Servant.Checked.Exceptions: relaxEnvelope :: Contains es biggerEs => Envelope es a -> Envelope biggerEs a
+ Servant.Checked.Exceptions: throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Envelope: EnvelopeT :: m (Envelope es a) -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Envelope: [runEnvelopeT] :: EnvelopeT es m a -> m (Envelope es a)
+ Servant.Checked.Exceptions.Envelope: bindEnvT :: (Contains es1 fullEs, Contains es2 fullEs, Monad m) => EnvelopeT es1 m a -> (a -> EnvelopeT es2 m b) -> EnvelopeT fullEs m b
+ Servant.Checked.Exceptions.Envelope: bindEnvelope :: (Contains es1 fullEs, Contains es2 fullEs) => Envelope es1 a -> (a -> Envelope es2 b) -> Envelope fullEs b
+ Servant.Checked.Exceptions.Envelope: catchesEnvT :: forall tuple es m a x. (Monad m, ToOpenProduct tuple (ReturnX (m x) es)) => tuple -> (a -> m x) -> EnvelopeT es m a -> m x
+ Servant.Checked.Exceptions.Envelope: data EnvelopeT es m a
+ Servant.Checked.Exceptions.Envelope: emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a
+ Servant.Checked.Exceptions.Envelope: envTRemove :: forall e es m a. (ElemRemove e es, Functor m) => EnvelopeT es m a -> EnvelopeT (Remove e es) m (Either a e)
+ Servant.Checked.Exceptions.Envelope: envTToExceptT :: Functor m => EnvelopeT es m a -> ExceptT (OpenUnion es) m a
+ Servant.Checked.Exceptions.Envelope: envelopeHandle :: ElemRemove e es => (Envelope (Remove e es) a -> x) -> (e -> x) -> Envelope es a -> x
+ Servant.Checked.Exceptions.Envelope: envelopeRemove :: forall e es a. ElemRemove e es => Envelope es a -> Either (Envelope (Remove e es) a) e
+ Servant.Checked.Exceptions.Envelope: envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c
+ Servant.Checked.Exceptions.Envelope: errEnvTMatch :: forall e es m a. (Functor m, IsMember e es) => EnvelopeT es m a -> m (Maybe e)
+ Servant.Checked.Exceptions.Envelope: exceptTToEnvT :: Functor m => ExceptT (OpenUnion es) m a -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Envelope: fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a
+ Servant.Checked.Exceptions.Envelope: fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a
+ Servant.Checked.Exceptions.Envelope: liftA2EnvT :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m) => (a -> b -> c) -> EnvelopeT es1 m a -> EnvelopeT es2 m b -> EnvelopeT fullEs m c
+ Servant.Checked.Exceptions.Envelope: liftA2Envelope :: (Contains es1 fullEs, Contains es2 fullEs) => (a -> b -> c) -> Envelope es1 a -> Envelope es2 b -> Envelope fullEs c
+ Servant.Checked.Exceptions.Envelope: pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Envelope: relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a
+ Servant.Checked.Exceptions.Envelope: relaxEnvelope :: Contains es biggerEs => Envelope es a -> Envelope biggerEs a
+ Servant.Checked.Exceptions.Envelope: throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Internal.Envelope: bindEnvelope :: (Contains es1 fullEs, Contains es2 fullEs) => Envelope es1 a -> (a -> Envelope es2 b) -> Envelope fullEs b
+ Servant.Checked.Exceptions.Internal.Envelope: envelopeHandle :: ElemRemove e es => (Envelope (Remove e es) a -> x) -> (e -> x) -> Envelope es a -> x
+ Servant.Checked.Exceptions.Internal.Envelope: envelopeRemove :: forall e es a. ElemRemove e es => Envelope es a -> Either (Envelope (Remove e es) a) e
+ Servant.Checked.Exceptions.Internal.Envelope: instance GHC.Show.Show (Data.WorldPeace.Union.OpenUnion es) => Data.Functor.Classes.Show1 (Servant.Checked.Exceptions.Internal.Envelope.Envelope es)
+ Servant.Checked.Exceptions.Internal.Envelope: liftA2Envelope :: (Contains es1 fullEs, Contains es2 fullEs) => (a -> b -> c) -> Envelope es1 a -> Envelope es2 b -> Envelope fullEs c
+ Servant.Checked.Exceptions.Internal.Envelope: relaxEnvelope :: Contains es biggerEs => Envelope es a -> Envelope biggerEs a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: EnvelopeT :: m (Envelope es a) -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: [runEnvelopeT] :: EnvelopeT es m a -> m (Envelope es a)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: bindEnvT :: (Contains es1 fullEs, Contains es2 fullEs, Monad m) => EnvelopeT es1 m a -> (a -> EnvelopeT es2 m b) -> EnvelopeT fullEs m b
+ Servant.Checked.Exceptions.Internal.EnvelopeT: catchesEnvT :: forall tuple es m a x. (Monad m, ToOpenProduct tuple (ReturnX (m x) es)) => tuple -> (a -> m x) -> EnvelopeT es m a -> m x
+ Servant.Checked.Exceptions.Internal.EnvelopeT: data EnvelopeT es m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: envTRemove :: forall e es m a. (ElemRemove e es, Functor m) => EnvelopeT es m a -> EnvelopeT (Remove e es) m (Either a e)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: envTToExceptT :: Functor m => EnvelopeT es m a -> ExceptT (OpenUnion es) m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c
+ Servant.Checked.Exceptions.Internal.EnvelopeT: errEnvTMatch :: forall e es m a. (Functor m, IsMember e es) => EnvelopeT es m a -> m (Maybe e)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: exceptTToEnvT :: Functor m => ExceptT (OpenUnion es) m a -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance (GHC.Show.Show (Data.WorldPeace.Union.OpenUnion e), Data.Functor.Classes.Show1 m, GHC.Show.Show a) => GHC.Show.Show (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT e m a)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance (GHC.Show.Show (Data.WorldPeace.Union.OpenUnion es), Data.Functor.Classes.Show1 m) => Data.Functor.Classes.Show1 (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.Error.Class.MonadError error m => Control.Monad.Error.Class.MonadError error (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.RWS.Class.MonadRWS r w s m => Control.Monad.RWS.Class.MonadRWS r w s (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.Trans.Class.MonadTrans (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Data.Foldable.Foldable m => Data.Foldable.Foldable (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Data.Functor.Contravariant.Contravariant m => Data.Functor.Contravariant.Contravariant (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance Data.Traversable.Traversable m => Data.Traversable.Traversable (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance GHC.Base.Functor m => GHC.Base.Functor (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance GHC.Base.Monad m => GHC.Base.Applicative (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: instance GHC.Base.Monad m => GHC.Base.Monad (Servant.Checked.Exceptions.Internal.EnvelopeT.EnvelopeT es m)
+ Servant.Checked.Exceptions.Internal.EnvelopeT: liftA2EnvT :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m) => (a -> b -> c) -> EnvelopeT es1 m a -> EnvelopeT es2 m b -> EnvelopeT fullEs m c
+ Servant.Checked.Exceptions.Internal.EnvelopeT: pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a
+ Servant.Checked.Exceptions.Internal.EnvelopeT: throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a

Files

CHANGELOG.md view
@@ -1,3 +1,17 @@+## 2.2.0.0++*   Add the `EnvelopeT` monad transformer. [#32]++*   Add a few combinators for `Envelope`:++        - `envelopeRemove`+        - `envelopeHandle`+        - `relaxEnvelope`+        - `liftA2Envelope`+        - `bindEnvelope`++    [#32]+ ## 2.1.0.0  *   Add support for servant-0.16 and remove support for all previous version of
servant-checked-exceptions-core.cabal view
@@ -1,5 +1,5 @@ name:                servant-checked-exceptions-core-version:             2.1.0.0+version:             2.2.0.0 synopsis:            Checked exceptions for Servant APIs. description:         Please see <https://github.com/cdepillabout/servant-checked-exceptions#readme README.md>. homepage:            https://github.com/cdepillabout/servant-checked-exceptions@@ -25,6 +25,7 @@                      , Servant.Checked.Exceptions.Verbs                      , Servant.Checked.Exceptions.Internal                      , Servant.Checked.Exceptions.Internal.Envelope+                     , Servant.Checked.Exceptions.Internal.EnvelopeT                      , Servant.Checked.Exceptions.Internal.Prism                      , Servant.Checked.Exceptions.Internal.Servant                      , Servant.Checked.Exceptions.Internal.Servant.API@@ -34,14 +35,18 @@   build-depends:       base >= 4.9 && < 5                      , aeson                      , bytestring+                       -- contravariant is needed for the Data.Functor.Contravariant module in GHC < 8.6+                     , contravariant >= 1.5                      , http-media                      , http-types+                     , mtl                      , profunctors                      , tagged+                     , transformers                      , servant >= 0.12                      , servant-docs >= 0.10                      , text-                     , world-peace+                     , world-peace >= 1.0.0.0   default-language:    Haskell2010   ghc-options:         -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction   other-extensions:    QuasiQuotes
src/Servant/Checked/Exceptions.hs view
@@ -86,6 +86,14 @@ <https://github.com/cdepillabout/servant-checked-exceptions/blob/master/example/Docs.hs documentation>. The <https://github.com/cdepillabout/servant-checked-exceptions README.md> shows how to compile and run the examples.++There is also an 'EnvelopeT' monad transformer.  'Envelope' and 'EnvelopeT'+have a similar relationship to 'Either' and 'ExceptT'.++The following is an example of how 'EnvelopeT' can be used:++<https://github.com/cdepillabout/servant-checked-exceptions/blob/master/example/EnvelopeT.hs EnvelopeT example>+ -}  module Servant.Checked.Exceptions@@ -152,6 +160,12 @@   , fromEnvelopeOrM   , errEnvelopeMatch   , catchesEnvelope+  , envelopeRemove+  , envelopeHandle+  -- ** Other 'Envelope' combinators+  , relaxEnvelope+  , liftA2Envelope+  , bindEnvelope   -- *** 'Envelope' optics   , _SuccEnvelope   , _ErrEnvelope@@ -160,18 +174,35 @@   , envelopeToEither   , eitherToEnvelope   , isoEnvelopeEither+  -- * 'EnvelopeT' short-circuiting monad transformer+  , EnvelopeT(..)+  -- ** 'EnvelopeT' helper functions+  -- *** 'EnvelopeT' constructors+  , pureSuccEnvT+  , throwErrEnvT+  -- ** 'EnvelopeT' destructors+  , envelopeT+  , fromEnvT+  , fromEnvTOr+  , errEnvTMatch+  , catchesEnvT+  , emptyEnvT+  , envTRemove+  -- ** Other 'EnvelopeT' combinators+  , relaxEnvT+  , liftA2EnvT+  , bindEnvT+  -- ** 'Envelope' and 'ExceptT'+  , envTToExceptT+  , exceptTToEnvT   -- * Re-exported modules   -- | "Data.WorldPeace" exports the 'OpenUnion' type as well as other   -- combinators.  It also exports the 'OpenProduct' type and 'ToProduct' type   -- class used by some of the functions above.   , module Data.WorldPeace-  , module Servant.Checked.Exceptions.Internal.Servant.Docs   ) where  import Data.WorldPeace import Network.HTTP.Types (Status) -import Servant.Checked.Exceptions.Internal.Envelope-import Servant.Checked.Exceptions.Internal.Servant.API-import Servant.Checked.Exceptions.Internal.Servant.Docs-import Servant.Checked.Exceptions.Internal.Verbs+import Servant.Checked.Exceptions.Internal
src/Servant/Checked/Exceptions/Envelope.hs view
@@ -2,12 +2,12 @@   -- * Envelope     Envelope(..)   -- * Helper functions-  -- ** Envelope Constructors+  -- ** Envelope constructors   , toSuccEnvelope   , toErrEnvelope   , pureSuccEnvelope   , pureErrEnvelope-  -- ** Envelope Destructors+  -- ** Envelope destructors   , envelope   , emptyEnvelope   , fromEnvelope@@ -16,6 +16,12 @@   , fromEnvelopeOrM   , errEnvelopeMatch   , catchesEnvelope+  , envelopeRemove+  , envelopeHandle+  -- ** Other Envelope combinators+  , relaxEnvelope+  , liftA2Envelope+  , bindEnvelope   -- ** Optics   , _SuccEnvelope   , _ErrEnvelope@@ -24,8 +30,28 @@   , envelopeToEither   , eitherToEnvelope   , isoEnvelopeEither+  -- * EnvelopeT+  , EnvelopeT(..)+  -- ** EnvelopeT constructors+  , pureSuccEnvT+  , throwErrEnvT+  -- ** EnvelopeT destructors+  , envelopeT+  , fromEnvT+  , fromEnvTOr+  , errEnvTMatch+  , catchesEnvT+  , emptyEnvT+  , envTRemove+  -- ** Other EnvelopeT combinators+  , relaxEnvT+  , liftA2EnvT+  , bindEnvT+  -- ** ExceptT+  , envTToExceptT+  , exceptTToEnvT   -- * Setup code for doctests   -- $setup   ) where -import Servant.Checked.Exceptions.Internal.Envelope+import Servant.Checked.Exceptions.Internal
src/Servant/Checked/Exceptions/Internal.hs view
@@ -1,11 +1,13 @@ module Servant.Checked.Exceptions.Internal   ( module Servant.Checked.Exceptions.Internal.Envelope+  , module Servant.Checked.Exceptions.Internal.EnvelopeT   , module Servant.Checked.Exceptions.Internal.Verbs   , module Servant.Checked.Exceptions.Internal.Servant   , module Servant.Checked.Exceptions.Internal.Util   ) where  import Servant.Checked.Exceptions.Internal.Envelope+import Servant.Checked.Exceptions.Internal.EnvelopeT import Servant.Checked.Exceptions.Internal.Verbs import Servant.Checked.Exceptions.Internal.Servant import Servant.Checked.Exceptions.Internal.Util
src/Servant/Checked/Exceptions/Internal/Envelope.hs view
@@ -45,17 +45,28 @@   ) import Data.Aeson.Types (Parser) import Data.Data (Data)+import Data.Functor.Classes+  ( Show1+  , liftShowsPrec+  , showsUnaryWith+  ) import Data.Semigroup (Semigroup((<>), stimes), stimesIdempotent) import Data.Typeable (Typeable) import Data.WorldPeace-  ( IsMember+  ( Contains+  , ElemRemove+  , IsMember   , OpenUnion+  , Remove   , ReturnX   , ToOpenProduct   , absurdUnion   , catchesOpenUnion+  , openUnionHandle   , openUnionLift   , openUnionPrism+  , openUnionRemove+  , relaxOpenUnion   ) import GHC.Generics (Generic) @@ -90,6 +101,88 @@ data Envelope es a = ErrEnvelope (OpenUnion es) | SuccEnvelope a   deriving (Foldable, Functor, Generic, Traversable) +-- | This 'ToJSON' instance encodes an 'Envelope' as an object with one of two+-- keys depending on whether it is a 'SuccEnvelope' or an 'ErrEnvelope'.+--+-- Here is an example of a 'SuccEnvelope':+--+-- >>> let string = "hello" :: String+-- >>> let env = toSuccEnvelope string :: Envelope '[Double] String+-- >>> putByteStrLn $ encode env+-- {"data":"hello"}+--+-- Here is an example of a 'ErrEnvelope':+--+-- >>> let double = 3.5 :: Double+-- >>> let env' = toErrEnvelope double :: Envelope '[Double] String+-- >>> putByteStrLn $ encode env'+-- {"err":3.5}+instance (ToJSON (OpenUnion es), ToJSON a) => ToJSON (Envelope es a) where+  toJSON :: Envelope es a -> Value+  toJSON (ErrEnvelope es) = object ["err" .= es]+  toJSON (SuccEnvelope a) = object ["data" .= a]++-- | This is only a valid instance when the 'FromJSON' instances for the @es@+-- don't overlap.+--+-- For an explanation, see the documentation on the 'FromJSON' instance for+-- 'Servant.Checked.Exceptions.Internal.Union.Union'.+instance (FromJSON (OpenUnion es), FromJSON a) => FromJSON (Envelope es a) where+  parseJSON :: Value -> Parser (Envelope es a)+  parseJSON = withObject "Envelope" $ \obj ->+    SuccEnvelope <$> obj .: "data" <|>+    ErrEnvelope <$> obj .: "err"++deriving instance (Data (OpenUnion es), Data a, Typeable es) => Data (Envelope es a)+deriving instance (Eq (OpenUnion es), Eq a) => Eq (Envelope es a)+deriving instance (Ord (OpenUnion es), Ord a) => Ord (Envelope es a)+deriving instance (Read (OpenUnion es), Read a) => Read (Envelope es a)+deriving instance (Show (OpenUnion es), Show a) => Show (Envelope es a)+deriving instance (Typeable (OpenUnion es), Typeable a) => Typeable (Envelope es a)++instance (Show (OpenUnion es)) => Show1 (Envelope es) where+  liftShowsPrec+    :: (Int -> a -> ShowS)+    -> ([a] -> ShowS)+    -> Int+    -> Envelope es a+    -> ShowS+  liftShowsPrec showA _ d (SuccEnvelope a) =+    showsUnaryWith showA "SuccEnvelope" d a+  liftShowsPrec _ _ d (ErrEnvelope es) =+    showsUnaryWith showsPrec "ErrEnvelope" d es++instance Applicative (Envelope es) where+  pure :: a -> Envelope es a+  pure = SuccEnvelope++  (<*>) :: Envelope es (a -> b) -> Envelope es a -> Envelope es b+  ErrEnvelope es <*> _ = ErrEnvelope es+  SuccEnvelope f <*> r = fmap f r++instance Monad (Envelope es) where+  (>>=) :: Envelope es a -> (a -> Envelope es b) -> Envelope es b+  ErrEnvelope es >>= _ = ErrEnvelope es+  SuccEnvelope a >>= k = k a++instance MonadFix (Envelope es) where+  mfix :: (a -> Envelope es a) -> Envelope es a+  mfix f =+    let a = f (unSucc a)+    in a+    where+      unSucc :: Envelope es a -> a+      unSucc (SuccEnvelope x) = x+      unSucc (ErrEnvelope _) = errorWithoutStackTrace "mfix Envelope: ErrEnvelope"++instance Semigroup (Envelope es a) where+  (<>) :: Envelope es a -> Envelope es a -> Envelope es a+  ErrEnvelope _ <> b = b+  a      <> _ = a++  stimes :: Integral b => b -> Envelope es a -> Envelope es a+  stimes = stimesIdempotent+ -- | Create an 'ErrEnvelope' from a member of the 'OpenUnion'. -- -- For instance, here is how to create an 'ErrEnvelope' that contains a@@ -106,13 +199,19 @@ -- >>> toSuccEnvelope "hello" :: Envelope '[Double] String -- SuccEnvelope "hello" toSuccEnvelope :: a -> Envelope es a-toSuccEnvelope = SuccEnvelope+toSuccEnvelope = pure  -- | 'pureErrEnvelope' is 'toErrEnvelope' lifted up to an 'Applicative'.+--+-- >>> pureErrEnvelope 'c' :: Maybe (Envelope '[Char] Int)+-- Just (ErrEnvelope (Identity 'c')) pureErrEnvelope :: (Applicative m, IsMember e es) => e -> m (Envelope es a) pureErrEnvelope = pure . toErrEnvelope  -- | 'pureSuccEnvelope' is 'toSuccEnvelope' lifted up to an 'Applicative'.+--+-- >>> pureSuccEnvelope 3 :: Maybe (Envelope '[Char] Int)+-- Just (SuccEnvelope 3) pureSuccEnvelope :: Applicative m => a -> m (Envelope es a) pureSuccEnvelope = pure . toSuccEnvelope @@ -136,6 +235,82 @@ envelope f _ (ErrEnvelope es) = f es envelope _ f (SuccEnvelope a) = f a +-- | Similar to 'liftA2', but more general.  This allows you to operate on two+-- 'Envelope's with different sets of errors.  The resulting 'Envelope' is a+-- combination of the errors in each of the input 'Envelope's.+--+-- ==== __Examples__+--+-- >>> let env1 = toSuccEnvelope "hello" :: Envelope '[Double, Int] String+-- >>> let env2 = toSuccEnvelope " world" :: Envelope '[Char] String+-- >>> liftA2Envelope (<>) env1 env2 :: Envelope '[Double, Int, Char] String+-- SuccEnvelope "hello world"+--+-- If either of the 'Envelope's is an 'ErrEnvelope', then return the 'ErrEnvelope'.+--+-- >>> let env3 = toErrEnvelope "some err" :: Envelope '[String, Double] Int+-- >>> let env4 = toSuccEnvelope 1 :: Envelope '[Char] Int+-- >>> liftA2Envelope (+) env3 env4 :: Envelope '[String, Double, Char] Int+-- ErrEnvelope (Identity "some err")+--+-- >>> let env5 = toSuccEnvelope "hello" :: Envelope '[Char] String+-- >>> let env6 = toErrEnvelope 3.5 :: Envelope '[(), Double] String+-- >>> liftA2Envelope (<>) env5 env6 :: Envelope '[Char, (), Double] String+-- ErrEnvelope (Identity 3.5)+--+-- If both of the 'Envelope's is an 'ErrEnvelope', then short-circuit and only+-- return the first 'ErrEnvelope'.+--+-- >>> let env7 = toErrEnvelope 3.5 :: Envelope '[(), Double] String+-- >>> let env8 = toErrEnvelope 'x' :: Envelope '[Int, Char] String+-- >>> liftA2Envelope (<>) env7 env8 :: Envelope '[(), Double, Int, Char] String+-- ErrEnvelope (Identity 3.5)+liftA2Envelope :: (Contains es1 fullEs, Contains es2 fullEs) => (a -> b -> c) -> Envelope es1 a -> Envelope es2 b -> Envelope fullEs c+liftA2Envelope f (SuccEnvelope a) (SuccEnvelope b) = SuccEnvelope (f a b)+liftA2Envelope _ (ErrEnvelope es) _ = ErrEnvelope (relaxOpenUnion es)+liftA2Envelope _ _ (ErrEnvelope es) = ErrEnvelope (relaxOpenUnion es)++-- | This is like 'liftA2Envelope' but for monadic bind ('>>=').+--+-- This allows you to bind on 'Envelope's that contain different errors.+--+-- The resulting 'Envelope' must have a superset of the errors in two input+-- 'Envelope's.+--+-- ==== __Examples__+--+-- >>> let env1 = toSuccEnvelope "hello" :: Envelope '[Double, Int] String+-- >>> let f1 str = toSuccEnvelope (length str) :: Envelope '[Char] Int+-- >>> bindEnvelope env1 f1 :: Envelope '[Double, Int, Char] Int+-- SuccEnvelope 5+--+-- If either of the 'Envelope's is an 'ErrEnvelope', then return the 'ErrEnvelope'.+--+-- >>> let env2 = toErrEnvelope "some err" :: Envelope '[String, Double] Int+-- >>> let f2 i = toSuccEnvelope (i + 1) :: Envelope '[Char] Int+-- >>> bindEnvelope env2 f2 :: Envelope '[String, Double, Char] Int+-- ErrEnvelope (Identity "some err")+--+-- >>> let env3 = toSuccEnvelope "hello" :: Envelope '[Char] String+-- >>> let f3 _ = toErrEnvelope 3.5 :: Envelope '[(), Double] Int+-- >>> bindEnvelope env3 f3 :: Envelope '[Char, (), Double] Int+-- ErrEnvelope (Identity 3.5)+--+-- If both of the 'Envelope's is an 'ErrEnvelope', then short-circuit and only+-- return the first 'ErrEnvelope'.+--+-- >>> let env4 = toErrEnvelope 3.5 :: Envelope '[(), Double] String+-- >>> let f4 _ = toErrEnvelope 'x' :: Envelope '[Int, Char] String+-- >>> bindEnvelope env4 f4 :: Envelope '[Char, (), Double, Int] String+-- ErrEnvelope (Identity 3.5)+bindEnvelope+  :: (Contains es1 fullEs, Contains es2 fullEs)+  => Envelope es1 a+  -> (a -> Envelope es2 b)+  -> Envelope fullEs b+bindEnvelope (SuccEnvelope a) f = relaxEnvelope $ f a+bindEnvelope (ErrEnvelope u) _ = relaxEnvelope (ErrEnvelope u)+ -- | Unwrap an 'Envelope' that cannot contain an error. -- -- ==== __Examples__@@ -395,72 +570,108 @@ catchesEnvelope _ a2x (SuccEnvelope a) = a2x a catchesEnvelope tuple _ (ErrEnvelope u) = catchesOpenUnion tuple u --- | This 'ToJSON' instance encodes an 'Envelope' as an object with one of two--- keys depending on whether it is a 'SuccEnvelope' or an 'ErrEnvelope'.+-- | Change the errors type in an 'Envelope' to a larger set. ----- Here is an example of a 'SuccEnvelope':+-- >>> let double = 3.5 :: Double+-- >>> let env = toErrEnvelope double :: Envelope '[Double, Int] Char+-- >>> relaxEnvelope env :: Envelope '[(), Int, Double, String] Char+-- ErrEnvelope (Identity 3.5)+relaxEnvelope :: Contains es biggerEs => Envelope es a -> Envelope biggerEs a+relaxEnvelope (SuccEnvelope a) = SuccEnvelope a+relaxEnvelope (ErrEnvelope u) = ErrEnvelope (relaxOpenUnion u)++-- | This function allows you to try to remove individual error types from an+-- 'Envelope'. ----- >>> let string = "hello" :: String--- >>> let env = toSuccEnvelope string :: Envelope '[Double] String--- >>> putByteStrLn $ encode env--- {"data":"hello"}+-- This can be used to handle only certain error types in an 'Envelope',+-- instead of having to handle all of them at the same time.  This can be more+-- convenient than a function like 'catchesEnvelope'. ----- Here is an example of a 'ErrEnvelope':+-- ==== __Examples__ ----- >>> let double = 3.5 :: Double--- >>> let env' = toErrEnvelope double :: Envelope '[Double] String--- >>> putByteStrLn $ encode env'--- {"err":3.5}-instance (ToJSON (OpenUnion es), ToJSON a) => ToJSON (Envelope es a) where-  toJSON :: Envelope es a -> Value-  toJSON (ErrEnvelope es) = object ["err" .= es]-  toJSON (SuccEnvelope a) = object ["data" .= a]---- | This is only a valid instance when the 'FromJSON' instances for the @es@--- don't overlap.+-- Pulling out an error in an 'Envelope': ----- For an explanation, see the documentation on the 'FromJSON' instance for--- 'Servant.Checked.Exceptions.Internal.Union.Union'.-instance (FromJSON (OpenUnion es), FromJSON a) => FromJSON (Envelope es a) where-  parseJSON :: Value -> Parser (Envelope es a)-  parseJSON = withObject "Envelope" $ \obj ->-    SuccEnvelope <$> obj .: "data" <|>-    ErrEnvelope <$> obj .: "err"--deriving instance (Data (OpenUnion es), Data a, Typeable es) => Data (Envelope es a)-deriving instance (Eq (OpenUnion es), Eq a) => Eq (Envelope es a)-deriving instance (Ord (OpenUnion es), Ord a) => Ord (Envelope es a)-deriving instance (Read (OpenUnion es), Read a) => Read (Envelope es a)-deriving instance (Show (OpenUnion es), Show a) => Show (Envelope es a)-deriving instance (Typeable (OpenUnion es), Typeable a) => Typeable (Envelope es a)--instance Applicative (Envelope es) where-  pure :: a -> Envelope es a-  pure = SuccEnvelope--  (<*>) :: Envelope es (a -> b) -> Envelope es a -> Envelope es b-  ErrEnvelope es <*> _ = ErrEnvelope es-  SuccEnvelope f <*> r = fmap f r--instance Monad (Envelope es) where-  (>>=) :: Envelope es a -> (a -> Envelope es b) -> Envelope es b-  ErrEnvelope es >>= _ = ErrEnvelope es-  SuccEnvelope a >>= k = k a--instance MonadFix (Envelope es) where-  mfix :: (a -> Envelope es a) -> Envelope es a-  mfix f =-    let a = f (unSucc a)-    in a-    where-      unSucc :: Envelope es a -> a-      unSucc (SuccEnvelope x) = x-      unSucc (ErrEnvelope _) = errorWithoutStackTrace "mfix Envelope: ErrEnvelope"--instance Semigroup (Envelope es a) where-  (<>) :: Envelope es a -> Envelope es a -> Envelope es a-  ErrEnvelope _ <> b = b-  a      <> _ = a+-- >>> let env1 = toErrEnvelope "hello" :: Envelope '[String, Double] Float+-- >>> envelopeRemove env1 :: Either (Envelope '[Double] Float) String+-- Right "hello"+--+-- Failing to pull out an error in an 'Envelope':+--+-- >>> let env2 = toErrEnvelope (3.5 :: Double) :: Envelope '[String, Double] Float+-- >>> envelopeRemove env2 :: Either (Envelope '[Double] Float) String+-- Left (ErrEnvelope (Identity 3.5))+--+-- Note that if you have an 'Envelope' with multiple errors of the same type,+-- they will all be handled at the same time:+--+-- >>> let env3 = toErrEnvelope (3.5 :: Double) :: Envelope '[String, Double, Char, Double] Float+-- >>> envelopeRemove env3 :: Either (Envelope '[String, Char] Float) Double+-- Right 3.5+--+-- 'SuccEnvelope' gets passed through as expected:+--+-- >>> let env4 = toSuccEnvelope 3.5 :: Envelope '[String, Double] Float+-- >>> envelopeRemove env4 :: Either (Envelope '[Double] Float) String+-- Left (SuccEnvelope 3.5)+envelopeRemove+  :: forall e es a+   . ElemRemove e es+  => Envelope es a+  -> Either (Envelope (Remove e es) a) e+envelopeRemove (SuccEnvelope a) = Left (SuccEnvelope a)+envelopeRemove (ErrEnvelope u) =+  case openUnionRemove u of+    Left u2 -> Left (ErrEnvelope u2)+    Right e -> Right e -  stimes :: Integral b => b -> Envelope es a -> Envelope es a-  stimes = stimesIdempotent+-- | Handle a single case in an 'Envelope'.  This is similar to 'envelope'+-- but lets you handle any case within the 'Envelope', not just the first one.+--+-- ==== __Examples__+--+-- Handling the first item in an 'Envelope':+--+-- >>> let env1 = toErrEnvelope 3.5 :: Envelope '[Double, Int] Char+-- >>> let printDouble = print :: Double -> IO ()+-- >>> let printEnv = print :: Envelope '[Int] Char -> IO ()+-- >>> envelopeHandle printEnv printDouble env1+-- 3.5+--+-- Handling a middle item in an 'Envelope':+--+-- >>> let env2 = toErrEnvelope (3.5 :: Double) :: Envelope '[Char, Double, Int] Float+-- >>> let printEnv = print :: Envelope '[Char, Int] Float -> IO ()+-- >>> envelopeHandle printEnv printDouble env2+-- 3.5+--+-- Failing to handle an item in an 'Envelope'.  In the following example, the+-- @printEnv@ function is called:+--+-- >>> let env3 = toErrEnvelope 'c' :: Envelope '[Char, Double, Int] Float+-- >>> let printEnv = print :: Envelope '[Char, Int] Float -> IO ()+-- >>> envelopeHandle printEnv printDouble env3+-- ErrEnvelope (Identity 'c')+--+-- If you have duplicates in your 'Envelope', they will both get handled with+-- a single call to 'unionHandle'.+--+-- >>> let env4 = toErrEnvelope 3.5 :: Envelope '[Double, Double, Int] Char+-- >>> let printEnv = print :: Envelope '[Int] Char -> IO ()+-- >>> envelopeHandle printEnv printDouble env4+-- 3.5+--+-- 'SuccEnvelope' gets passed through as expected:+--+-- >>> let env5 = toSuccEnvelope 3.5 :: Envelope '[String, Double] Float+-- >>> let printEnv = print :: Envelope '[String] Float -> IO ()+-- >>> envelopeHandle printEnv printDouble env5+-- SuccEnvelope 3.5+envelopeHandle+  :: ElemRemove e es+  => (Envelope (Remove e es) a -> x)+  -> (e -> x)+  -> Envelope es a+  -> x+envelopeHandle handler _ (SuccEnvelope a) = handler (SuccEnvelope a)+envelopeHandle handler errHandler (ErrEnvelope u) =+  openUnionHandle (handler . ErrEnvelope) errHandler u
+ src/Servant/Checked/Exceptions/Internal/EnvelopeT.hs view
@@ -0,0 +1,508 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}++{- |+Module      :  Servant.Checked.Exceptions.Internal.EnvelopeT++Copyright   :  Dennis Gosnell 2019+License     :  BSD3++Maintainer  :  Dennis Gosnell (cdep.illabout@gmail.com)+Stability   :  experimental+Portability :  unknown++This module defines the 'EnvelopeT' type and helper functions. 'EnvelopeT' is a+short-circuiting monad transformer.++'Envelope' is similar to 'Either' where multiple errors types are possible.+'EnvelopeT' is similar to 'ExceptT' in a similar manner.+-}++module Servant.Checked.Exceptions.Internal.EnvelopeT where++import Control.Monad.Except (ExceptT(ExceptT), MonadError(throwError, catchError))+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Reader (MonadReader, ask, local, reader)+import Control.Monad.RWS (MonadRWS)+import Control.Monad.State (MonadState, get, put, state)+import Control.Monad.Trans.Class (MonadTrans(lift))+import Control.Monad.Writer (MonadWriter, listen, pass, tell, writer)+import Data.Functor.Classes+  ( Show1+  , liftShowList+  , liftShowsPrec+  , showsPrec1+  , showsUnaryWith+  )+import Data.Functor.Contravariant (Contravariant(contramap))+import Data.WorldPeace+  ( Contains+  , ElemRemove+  , IsMember+  , OpenUnion+  , Remove+  , ReturnX+  , ToOpenProduct+  , relaxOpenUnion+  )++import Servant.Checked.Exceptions.Internal.Envelope+  ( Envelope(ErrEnvelope, SuccEnvelope)+  , catchesEnvelope+  , liftA2Envelope+  , eitherToEnvelope+  , emptyEnvelope+  , envelope+  , envelopeRemove+  , envelopeToEither+  , errEnvelopeMatch+  , pureErrEnvelope+  , pureSuccEnvelope+  , relaxEnvelope+  )++-- $setup+-- >>> :set -XDataKinds+-- >>> :set -XTypeOperators+-- >>> import Data.Functor.Identity (Identity(Identity))++data EnvelopeT es m a = EnvelopeT+  { runEnvelopeT :: m (Envelope es a)+  } deriving Functor++instance (Show (OpenUnion es), Show1 m) => Show1 (EnvelopeT es m) where+  liftShowsPrec+    :: forall a+     . (Int -> a -> ShowS)+    -> ([a] -> ShowS)+    -> Int+    -> EnvelopeT es m a -> ShowS+  liftShowsPrec sp sl d (EnvelopeT m) =+    showsUnaryWith showInnerM "EnvelopeT" d m+    where+      showInnerM :: Int -> m (Envelope es a) -> ShowS+      showInnerM = liftShowsPrec sp' sl'++      sp' :: Int -> Envelope es a -> ShowS+      sp' = liftShowsPrec sp sl++      sl' :: [Envelope es a] -> ShowS+      sl' = liftShowList sp sl++instance (Show (OpenUnion e), Show1 m, Show a) => Show (EnvelopeT e m a) where+  showsPrec = showsPrec1++instance Monad m => Applicative (EnvelopeT es m) where+  pure :: a -> EnvelopeT es m a+  pure a = EnvelopeT $ pureSuccEnvelope a++  (<*>) :: EnvelopeT es m (a -> b) -> EnvelopeT es m a -> EnvelopeT es m b+  EnvelopeT a2b <*> EnvelopeT a = EnvelopeT $ go <$> a2b <*> a+    where+      go :: Envelope es (a -> b) -> Envelope es a -> Envelope es b+      go = (<*>)++instance Monad m => Monad (EnvelopeT es m) where+  (>>=) :: EnvelopeT es m a -> (a -> EnvelopeT es m b) -> EnvelopeT es m b+  (EnvelopeT m) >>= k = EnvelopeT $ do+    env <- m+    case env of+      SuccEnvelope a -> runEnvelopeT $ k a+      ErrEnvelope err -> pure $ ErrEnvelope err++instance MonadTrans (EnvelopeT es) where+  lift :: Monad m => m a -> EnvelopeT es m a+  lift m = EnvelopeT $ do+    val <- m+    pureSuccEnvelope val++instance MonadIO m => MonadIO (EnvelopeT es m) where+  liftIO :: IO a -> EnvelopeT es m a+  liftIO = lift . liftIO++instance Foldable m => Foldable (EnvelopeT es m) where+  foldMap f (EnvelopeT m) = foldMap (envelope (const mempty) f) m++instance (Traversable m) => Traversable (EnvelopeT es m) where+  traverse+    :: Applicative f => (a -> f b) -> EnvelopeT es m a -> f (EnvelopeT es m b)+  traverse f (EnvelopeT m) =+    fmap EnvelopeT $+      traverse (envelope (pure . ErrEnvelope) (fmap SuccEnvelope . f)) m++instance Contravariant m => Contravariant (EnvelopeT es m) where+  contramap :: (b -> a) -> EnvelopeT es m a -> EnvelopeT es m b+  contramap f (EnvelopeT m) = EnvelopeT $ contramap (fmap f) m++instance MonadRWS r w s m => MonadRWS r w s (EnvelopeT es m)++instance MonadError error m => MonadError error (EnvelopeT es m) where+  throwError = EnvelopeT . throwError++  catchError+    :: forall a+     . EnvelopeT es m a+    -> (error -> EnvelopeT es m a)+    -> EnvelopeT es m a+  catchError (EnvelopeT m) handler = EnvelopeT $ catchError m innerRunner+    where+      innerRunner :: error -> m (Envelope es a)+      innerRunner = runEnvelopeT . handler++instance MonadReader r m => MonadReader r (EnvelopeT es m) where+  ask = lift ask+  local f (EnvelopeT m) = EnvelopeT (local f m)+  reader = lift . reader++instance MonadState s m => MonadState s (EnvelopeT es m) where+  get = lift get+  put = lift . put+  state = lift . state++instance MonadWriter w m => MonadWriter w (EnvelopeT es m) where+  writer = lift . writer+  tell = lift . tell+  listen (EnvelopeT m) =+    EnvelopeT $ do+      (envelopeA, w) <- listen m+      pure $ fmap (,w) envelopeA+  pass (EnvelopeT m) =+    EnvelopeT $ do+      envel <- m+      pass . pure $+        case envel of+          SuccEnvelope (a, f) -> (SuccEnvelope a, f)+          ErrEnvelope es -> (ErrEnvelope es, id)++-- | This is 'pure' for 'EnvelopeT'.+--+-- >>> pureSuccEnvT "hello" :: EnvelopeT '[] Identity String+-- EnvelopeT (Identity (SuccEnvelope "hello"))+pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a+pureSuccEnvT = EnvelopeT . pureSuccEnvelope++-- | Throw an error in an 'ErrEnvelope'.+--+-- >>> let double = 3.5 :: Double+-- >>> throwErrEnvT double :: EnvelopeT '[String, Double, Int] Identity ()+-- EnvelopeT (Identity (ErrEnvelope (Identity 3.5)))+--+-- This is similar to 'throwError', but is specialized so you can throw just+-- one of the error types.+throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a+throwErrEnvT = EnvelopeT . pureErrEnvelope++-- | Case analysis for 'EnvelopeT'.+--+-- ==== __Examples__+--+--  Here is an example of matching on a 'SuccEnvelope':+--+-- >>> let env = pure "hello" :: EnvelopeT '[Double, Int] Identity String+-- >>> envelopeT (\_ -> Identity "not a String") Identity env+-- Identity "hello"+--+-- Here is an example of matching on a 'ErrEnvelope':+--+-- >>> let double = 3.5 :: Double+-- >>> let env' = throwErrEnvT double :: EnvelopeT '[Double, Int] Identity String+-- >>> envelopeT (\_ -> Identity "not a String") Identity env'+-- Identity "not a String"+envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c+envelopeT errHandler succHandler (EnvelopeT m) = do+  envel <- m+  envelope errHandler succHandler envel++-- | Slight simplification of 'envelopeT'.+--+-- ==== __Examples__+--+--  Here is an example of successfully matching:+--+-- >>> let env = pure "hello" :: EnvelopeT '[Double, Int] Identity String+-- >>> fromEnvT (\_ -> Identity "not a String") env+-- Identity "hello"+--+-- Here is an example of unsuccessfully matching:+--+-- >>> let double = 3.5 :: Double+-- >>> let env' = throwErrEnvT double :: EnvelopeT '[Double, Int] Identity String+-- >>> fromEnvT (\_ -> Identity "not a String") env'+-- Identity "not a String"+fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a+fromEnvT f = envelopeT f pure++-- | Flipped version of 'fromEnvT'.+fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a+fromEnvTOr = flip fromEnvT++-- | Try to pull out a specific @e@ from an 'ErrEnvelope'.+--+-- ==== __Examples__+--+-- Successfully pull out an @e@:+--+-- >>> let double = 3.5 :: Double+-- >>> let env = throwErrEnvT double :: EnvelopeT '[Double, Char] Identity ()+-- >>> errEnvTMatch env :: Identity (Maybe Double)+-- Identity (Just 3.5)+--+-- Unsuccessfully pull out an @e@:+--+-- >>> let env' = pure () :: EnvelopeT '[String, Double] Identity ()+-- >>> errEnvTMatch env' :: Identity (Maybe Double)+-- Identity Nothing+errEnvTMatch+  :: forall e es m a.+     (Functor m, IsMember e es)+  => EnvelopeT es m a+  -> m (Maybe e)+errEnvTMatch (EnvelopeT m) = fmap errEnvelopeMatch m++-- | An alternate case anaylsis for an 'EnvelopeT'.  This method uses a tuple+-- containing handlers for each potential value of the underlying 'Envelope'.+-- This is somewhat similar to the 'Control.Exception.catches' function.+--+-- When working with an 'Envelope' with a large number of possible error types,+-- it can be easier to use 'catchesEnvT' than 'envelopeT'.+--+-- ==== __Examples__+--+-- Here is an example of handling an 'SuccEnvelope' with two possible error values.+-- Notice that a normal tuple is used:+--+-- >>> let env = pure 2.0 :: EnvelopeT '[Int, String] IO Double+-- >>> let intHandler = (\int -> pure $ show int) :: Int -> IO String+-- >>> let strHandler = (\str -> pure str) :: String -> IO String+-- >>> let succHandler = (\dbl -> pure "got a double") :: Double -> IO String+-- >>> catchesEnvT (intHandler, strHandler) succHandler env :: IO String+-- "got a double"+--+-- Here is an example of handling an 'ErrEnvelope' with two possible error values.+-- Notice that a normal tuple is used to hold the handlers:+--+-- >>> let env = throwErrEnvT (3 :: Int) :: EnvelopeT '[Int, String] Identity Double+-- >>> let intHandler = (\int -> Identity $ show int) :: Int -> Identity String+-- >>> let strHandler = (\str -> Identity str) :: String -> Identity String+-- >>> let succHandler = (\dbl -> Identity "got a double") :: Double -> Identity String+-- >>> catchesEnvT (intHandler, strHandler) succHandler env :: Identity String+-- Identity "3"+--+-- Given an 'EnvelopeT' like @'EnvelopeT' \'['Int', 'String'] 'IO' 'Double'@,+-- the type of 'catchesEnvT' becomes the following:+--+-- @+--   'catchesEnvT'+--     :: ('Int' -> 'IO' x, 'String' -> 'IO' x)+--     -> ('Double' -> 'IO' x)+--     -> 'EnvelopeT' \'['Int', 'String'] 'IO' 'Double'+--     -> 'IO' x+-- @+--+-- Here is an example of handling an 'ErrEnvelope' with three possible values.+-- Notice how a 3-tuple is used to hold the handlers:+--+-- >>> let env = throwErrEnvT ("hi" :: String) :: EnvelopeT '[Int, String, Char] IO Double+-- >>> let intHandler = (\int -> pure $ show int) :: Int -> IO String+-- >>> let strHandler = (\str -> pure str) :: String -> IO String+-- >>> let chrHandler = (\chr -> pure [chr]) :: Char -> IO String+-- >>> let succHandler = (\dbl -> pure "got a double") :: Double -> IO String+-- >>> catchesEnvT (intHandler, strHandler, chrHandler) succHandler env :: IO String+-- "hi"+--+-- Given an 'Envelope' like @'EnvelopeT' \'['Int', 'String', 'Char'] 'IO' 'Double'@,+-- the type of 'catchesEnvT' becomes the following:+--+-- @+--   'catchesEnvT'+--     :: ('Int' -> 'IO' x, 'String' -> 'IO' x, 'Char' -> 'IO' x)+--     -> ('Double' -> 'IO' x)+--     -> 'EnvelopeT' \'['Int', 'String', 'Char'] 'IO' 'Double'+--     -> x+-- @+catchesEnvT+  :: forall tuple es m a x+   .  (Monad m, ToOpenProduct tuple (ReturnX (m x) es))+  => tuple -> (a -> m x) -> EnvelopeT es m a -> m x+catchesEnvT tuple a2mx (EnvelopeT m) = do+  envel <- m+  catchesEnvelope tuple a2mx envel++-- | Convert an 'EnvelopeT' to an 'ExceptT'.+envTToExceptT :: Functor m => EnvelopeT es m a -> ExceptT (OpenUnion es) m a+envTToExceptT (EnvelopeT m) = ExceptT $ fmap envelopeToEither m++-- | Convert an 'ExceptT' to an 'EnvelopeT'.+exceptTToEnvT :: Functor m => ExceptT (OpenUnion es) m a -> EnvelopeT es m a+exceptTToEnvT (ExceptT m) = EnvelopeT $ fmap eitherToEnvelope m++-- | Safely unwrap an 'EnvelopeT'.+--+-- >>> let myenvT = pure "hello" :: EnvelopeT '[] IO String+-- >>> emptyEnvT myenvT :: IO String+-- "hello"+emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a+emptyEnvT (EnvelopeT m) = fmap emptyEnvelope m++-- | Change the errors type in an 'EnvelopeT' to a larger set.+--+-- ==== __Examples__+--+-- >>> let double = 3.5 :: Double+-- >>> let envT1 = throwErrEnvT double :: EnvelopeT '[Int, Double] Identity Float+-- >>> relaxEnvT envT1 :: EnvelopeT '[Char, Int, String, Double] Identity Float+-- EnvelopeT (Identity (ErrEnvelope (Identity 3.5)))+--+-- >>> let envT2 = pure double :: EnvelopeT '[Char, Int] Identity Double+-- >>> relaxEnvT envT2 :: EnvelopeT '[(), Char, String, Int] Identity Double+-- EnvelopeT (Identity (SuccEnvelope 3.5))+relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a+relaxEnvT (EnvelopeT m) = EnvelopeT $ fmap relaxEnvelope m++-- | Combine two 'EnvelopeT's.  Generalize the set of errors to include the errors+-- from both 'EnvelopeT's. Similar to 'liftA2' but more general.+--+-- ==== __Examples__+--+-- >>> let env1 = pure "hello" :: EnvelopeT '[Double, Int] Identity String+-- >>> let env2 = pure " world" :: EnvelopeT '[Char]  Identity String+-- >>> liftA2EnvT (<>) env1 env2 :: EnvelopeT '[Double, Int, Char] Identity String+-- EnvelopeT (Identity (SuccEnvelope "hello world"))+--+-- If either of the 'Envelope's is an 'ErrEnvelope', then return the 'ErrEnvelope'.+--+-- >>> let env3 = throwErrEnvT "some err" :: EnvelopeT '[String, Double] Identity Int+-- >>> let env4 = pure 1 :: EnvelopeT '[Char]  Identity Int+-- >>> liftA2EnvT (+) env3 env4 :: EnvelopeT '[String, Double, Char] Identity Int+-- EnvelopeT (Identity (ErrEnvelope (Identity "some err")))+--+-- >>> let env5 = pure "hello" :: EnvelopeT '[Char] Identity String+-- >>> let env6 = throwErrEnvT 3.5 :: EnvelopeT '[(), Double] Identity String+-- >>> liftA2EnvT (<>) env5 env6 :: EnvelopeT '[Char, (), Double] Identity String+-- EnvelopeT (Identity (ErrEnvelope (Identity 3.5)))+--+-- If both of the 'EnvelopeT's is an 'ErrEnvelope', then short-circuit and only+-- return the first 'ErrEnvelope'.+--+-- >>> let env7 = throwErrEnvT 4.5 :: EnvelopeT '[(), Double] Identity String+-- >>> let env8 = throwErrEnvT 'x' :: EnvelopeT '[Int, Char] Identity String+-- >>> liftA2EnvT (<>) env7 env8 :: EnvelopeT '[(), Double, Int, Char] Identity String+-- EnvelopeT (Identity (ErrEnvelope (Identity 4.5)))+liftA2EnvT+  :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m)+  => (a -> b -> c)+  -> EnvelopeT es1 m a+  -> EnvelopeT es2 m b+  -> EnvelopeT fullEs m c+liftA2EnvT f (EnvelopeT m) (EnvelopeT n) =+  EnvelopeT $ liftA2Envelope f <$> m <*> n++-- | This is like 'liftA2EnvT' but for monadic bind ('>>=').+--+-- This allows you to bind on 'EnvelopeT's that contain different errors.+--+-- The resulting 'EnvelopeT' must have a superset of the errors in two input+-- 'EnvelopeT's.+--+-- ==== __Examples__+--+-- >>> let env1 = pure "hello" :: EnvelopeT '[Double, Int] Identity String+-- >>> let f1 str = pure (length str) :: EnvelopeT '[Char] Identity Int+-- >>> bindEnvT env1 f1 :: EnvelopeT '[Double, Int, Char] Identity Int+-- EnvelopeT (Identity (SuccEnvelope 5))+--+-- If either of the 'EnvelopeT's holds an 'ErrEnvelope', then return the 'ErrEnvelope'.+--+-- >>> let env2 = throwErrEnvT "some err" :: EnvelopeT '[String, Double] Identity Int+-- >>> let f2 i = pureSuccEnvT (i + 1) :: EnvelopeT '[Char] Identity Int+-- >>> bindEnvT env2 f2 :: EnvelopeT '[String, Double, Char] Identity Int+-- EnvelopeT (Identity (ErrEnvelope (Identity "some err")))+--+-- >>> let env3 = pureSuccEnvT "hello" :: EnvelopeT '[Char] Identity String+-- >>> let f3 _ = throwErrEnvT 3.5 :: EnvelopeT '[(), Double] Identity Int+-- >>> bindEnvT env3 f3 :: EnvelopeT '[Char, (), Double] Identity Int+-- EnvelopeT (Identity (ErrEnvelope (Identity 3.5)))+--+-- If both of the 'Envelope's is an 'ErrEnvelope', then short-circuit and only+-- return the first 'ErrEnvelope'.+--+-- >>> let env4 = throwErrEnvT 3.5 :: EnvelopeT '[(), Double] Maybe String+-- >>> let f4 _ = throwErrEnvT 'x' :: EnvelopeT '[Int, Char] Maybe String+-- >>> bindEnvT env4 f4 :: EnvelopeT '[Char, (), Double, Int] Maybe String+-- EnvelopeT (Just (ErrEnvelope (Identity 3.5)))+bindEnvT+  :: (Contains es1 fullEs, Contains es2 fullEs, Monad m)+  => EnvelopeT es1 m a+  -> (a -> EnvelopeT es2 m b)+  -> EnvelopeT fullEs m b+bindEnvT (EnvelopeT m) f =+  EnvelopeT $ do+    envel1 <- m+    case envel1 of+      SuccEnvelope a ->+        let x = f a+        in runEnvelopeT $ relaxEnvT x+      ErrEnvelope u ->+        let fullEs = relaxOpenUnion u+        in pure $ ErrEnvelope fullEs++-- | This function allows you to try to remove individual error types from an+-- 'EnvelopeT'.+--+-- This can be used to handle only certain error types in an 'Envelope',+-- instead of having to handle all of them at the same time.  This can be more+-- convenient than a function like 'catchesEnvT'.+--+-- ==== __Examples__+--+-- Pulling out an error in an 'EnvelopeT':+--+-- >>> let env1 = throwErrEnvT "hello" :: EnvelopeT '[String, Double] Identity Float+-- >>> envTRemove env1 :: EnvelopeT '[Double] Identity (Either Float String)+-- EnvelopeT (Identity (SuccEnvelope (Right "hello")))+--+-- Failing to pull out an error in an 'EnvelopeT':+--+-- >>> let env2 = throwErrEnvT (3.5 :: Double) :: EnvelopeT '[String, Double] Identity Float+-- >>> envTRemove env2 :: EnvelopeT '[Double] Identity (Either Float String)+-- EnvelopeT (Identity (ErrEnvelope (Identity 3.5)))+--+-- Note that if you have an 'EnvelopeT' with multiple errors of the same type,+-- they will all be handled at the same time:+--+-- >>> let env3 = throwErrEnvT (3.5 :: Double) :: EnvelopeT '[String, Double, Char, Double] Identity Float+-- >>> envTRemove env3 :: EnvelopeT '[String, Char] Identity (Either Float Double)+-- EnvelopeT (Identity (SuccEnvelope (Right 3.5)))+--+-- 'SuccEnvelope' gets passed through as expected:+--+-- >>> let env4 = pureSuccEnvT 3.5 :: EnvelopeT '[String, Double] Identity Float+-- >>> envTRemove env4 :: EnvelopeT '[Double] Identity (Either Float String)+-- EnvelopeT (Identity (SuccEnvelope (Left 3.5)))+envTRemove+  :: forall e es m a+   . (ElemRemove e es, Functor m)+  => EnvelopeT es m a+  -> EnvelopeT (Remove e es) m (Either a e)+envTRemove (EnvelopeT m) = EnvelopeT $ fmap go m+  where+  go :: Envelope es a -> Envelope (Remove e es) (Either a e)+  go envel =+    case envelopeRemove envel of+      Right e -> SuccEnvelope (Right e)+      Left envel -> fmap Left envel