Copyright | Dennis Gosnell 2019 |
---|---|
License | BSD3 |
Maintainer | Dennis Gosnell (cdep.illabout@gmail.com) |
Stability | experimental |
Portability | unknown |
Safe Haskell | None |
Language | Haskell2010 |
Synopsis
- data EnvelopeT es m a = EnvelopeT {
- runEnvelopeT :: m (Envelope es a)
- pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a
- throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a
- envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c
- fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a
- fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a
- errEnvTMatch :: forall e es m a. (Functor m, IsMember e es) => EnvelopeT es m a -> m (Maybe e)
- 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
- envTToExceptT :: Functor m => EnvelopeT es m a -> ExceptT (OpenUnion es) m a
- exceptTToEnvT :: Functor m => ExceptT (OpenUnion es) m a -> EnvelopeT es m a
- emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a
- relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a
- liftA2EnvT :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m) => (a -> b -> c) -> EnvelopeT es1 m a -> EnvelopeT es2 m b -> EnvelopeT fullEs m c
- bindEnvT :: (Contains es1 fullEs, Contains es2 fullEs, Monad m) => EnvelopeT es1 m a -> (a -> EnvelopeT es2 m b) -> EnvelopeT fullEs m b
- envTRemove :: forall e es m a. (ElemRemove e es, Functor m) => EnvelopeT es m a -> EnvelopeT (Remove e es) m (Either a e)
Documentation
>>>
:set -XDataKinds
>>>
:set -XTypeOperators
>>>
import Data.Functor.Identity (Identity(Identity))
data EnvelopeT es m a Source #
EnvelopeT | |
|
Instances
pureSuccEnvT :: Applicative m => a -> EnvelopeT es m a Source #
throwErrEnvT :: (Applicative m, IsMember e es) => e -> EnvelopeT es m a Source #
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.
envelopeT :: Monad m => (OpenUnion es -> m c) -> (a -> m c) -> EnvelopeT es m a -> m c Source #
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"
fromEnvT :: Monad m => (OpenUnion es -> m a) -> EnvelopeT es m a -> m a Source #
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"
fromEnvTOr :: Monad m => EnvelopeT es m a -> (OpenUnion es -> m a) -> m a Source #
Flipped version of fromEnvT
.
errEnvTMatch :: forall e es m a. (Functor m, IsMember e es) => EnvelopeT es m a -> m (Maybe e) Source #
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
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 Source #
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 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
,
the type of EnvelopeT
'[Int
, String
] IO
Double
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
,
the type of EnvelopeT
'[Int
, String
, Char
] IO
Double
catchesEnvT
becomes the following:
catchesEnvT
:: (Int
->IO
x,String
->IO
x,Char
->IO
x) -> (Double
->IO
x) ->EnvelopeT
'[Int
,String
,Char
]IO
Double
-> x
emptyEnvT :: Functor m => EnvelopeT '[] m a -> m a Source #
Safely unwrap an EnvelopeT
.
>>>
let myenvT = pure "hello" :: EnvelopeT '[] IO String
>>>
emptyEnvT myenvT :: IO String
"hello"
relaxEnvT :: (Functor m, Contains es1 es2) => EnvelopeT es1 m a -> EnvelopeT es2 m a Source #
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))
liftA2EnvT :: (Contains es1 fullEs, Contains es2 fullEs, Applicative m) => (a -> b -> c) -> EnvelopeT es1 m a -> EnvelopeT es2 m b -> EnvelopeT fullEs m c Source #
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)))
bindEnvT :: (Contains es1 fullEs, Contains es2 fullEs, Monad m) => EnvelopeT es1 m a -> (a -> EnvelopeT es2 m b) -> EnvelopeT fullEs m b Source #
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)))
envTRemove :: forall e es m a. (ElemRemove e es, Functor m) => EnvelopeT es m a -> EnvelopeT (Remove e es) m (Either a e) Source #
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)))