Copyright | Dennis Gosnell 2017 |
---|---|
License | BSD3 |
Maintainer | Dennis Gosnell (cdep.illabout@gmail.com) |
Stability | experimental |
Portability | unknown |
Safe Haskell | None |
Language | Haskell2010 |
- data Envelope es a
- = ErrEnvelope (OpenUnion es)
- | SuccEnvelope a
- toSuccEnvelope :: a -> Envelope es a
- toErrEnvelope :: IsMember e es => e -> Envelope es a
- pureSuccEnvelope :: Applicative m => a -> m (Envelope es a)
- pureErrEnvelope :: (Applicative m, IsMember e es) => e -> m (Envelope es a)
- envelope :: (OpenUnion es -> c) -> (a -> c) -> Envelope es a -> c
- fromEnvelope :: (OpenUnion es -> a) -> Envelope es a -> a
- fromEnvelopeOr :: Envelope es a -> (OpenUnion es -> a) -> a
- fromEnvelopeM :: Applicative m => (OpenUnion es -> m a) -> Envelope es a -> m a
- fromEnvelopeOrM :: Applicative m => Envelope es a -> (OpenUnion es -> m a) -> m a
- errEnvelopeMatch :: forall e es a. IsMember e es => Envelope es a -> Maybe e
- catchesEnvelope :: forall tuple es a x. ToOpenProduct tuple (ReturnX x es) => tuple -> (a -> x) -> Envelope es a -> x
- _SuccEnvelope :: Prism (Envelope es a) (Envelope es b) a b
- _ErrEnvelope :: Prism (Envelope es a) (Envelope es' a) (OpenUnion es) (OpenUnion es')
- _ErrEnvelopeErr :: forall e es a. IsMember e es => Prism' (Envelope es a) e
- envelopeToEither :: Envelope es a -> Either (OpenUnion es) a
- eitherToEnvelope :: Either (OpenUnion es) a -> Envelope es a
- isoEnvelopeEither :: Iso (Envelope es a) (Envelope fs b) (Either (OpenUnion es) a) (Either (OpenUnion fs) b)
Envelope
This Envelope
type is a used as a wrapper around either an OpenUnion
with an error or a successful value. It is similar to an
,
but where the Either
e ae
is specialized to
. The most important
difference from OpenUnion
esEither
is the the FromJSON
and ToJSON
instances.
Given an
, we know that the envelope
could be a Envelope
'[String
, Double
] ()SuccEnvelope
and contain ()
. Or it could be a ErrEnvelope
that contains either a String
or a Double
. It might be simpler to
think of it as a type like
.Either
String
(Either
Double
())
An Envelope
can be created with the toErrEnvelope
and toSuccEnvelope
functions. The Prism
s _SuccEnvelope
, _ErrEnvelope
, and
_ErrEnvelopeErr
can be used to get values out of an Envelope
.
ErrEnvelope (OpenUnion es) | |
SuccEnvelope a |
Monad (Envelope es) Source # | |
Functor (Envelope es) Source # | |
MonadFix (Envelope es) Source # | |
Applicative (Envelope es) Source # | |
Foldable (Envelope es) Source # | |
Traversable (Envelope es) Source # | |
(Eq (OpenUnion es), Eq a) => Eq (Envelope es a) Source # | |
(Data (OpenUnion es), Data a, Typeable [*] es) => Data (Envelope es a) Source # | |
(Ord (OpenUnion es), Ord a) => Ord (Envelope es a) Source # | |
(Read (OpenUnion es), Read a) => Read (Envelope es a) Source # | |
(Show (OpenUnion es), Show a) => Show (Envelope es a) Source # | |
Generic (Envelope es a) Source # | |
Semigroup (Envelope es a) Source # | |
(ToJSON (OpenUnion es), ToJSON a) => ToJSON (Envelope es a) Source # | This Here is an example of a
Here is an example of a
|
(FromJSON (OpenUnion es), FromJSON a) => FromJSON (Envelope es a) Source # | This is only a valid instance when the For an explanation, see the documentation on the |
type Rep (Envelope es a) Source # | |
Helper functions
Envelope Constructors
toSuccEnvelope :: a -> Envelope es a Source #
This is a function to create a SuccEnvelope
.
>>>
toSuccEnvelope "hello" :: Envelope '[Double] String
SuccEnvelope "hello"
toErrEnvelope :: IsMember e es => e -> Envelope es a Source #
Create an ErrEnvelope
from a member of the OpenUnion
.
For instance, here is how to create an ErrEnvelope
that contains a
Double
:
>>>
let double = 3.5 :: Double
>>>
toErrEnvelope double :: Envelope '[String, Double, Int] ()
ErrEnvelope (Identity 3.5)
pureSuccEnvelope :: Applicative m => a -> m (Envelope es a) Source #
pureSuccEnvelope
is toSuccEnvelope
lifted up to an Applicative
.
pureErrEnvelope :: (Applicative m, IsMember e es) => e -> m (Envelope es a) Source #
pureErrEnvelope
is toErrEnvelope
lifted up to an Applicative
.
Envelope Destructors
envelope :: (OpenUnion es -> c) -> (a -> c) -> Envelope es a -> c Source #
Case analysis for Envelope
s.
Here is an example of matching on a SuccEnvelope
:
>>>
let env = toSuccEnvelope "hello" :: Envelope '[Double, Int] String
>>>
envelope (const "not a String") id env
"hello"
Here is an example of matching on a ErrEnvelope
:
>>>
let double = 3.5 :: Double
>>>
let env' = toErrEnvelope double :: Envelope '[Double, Int] String
>>>
envelope (const "not a String") id env'
"not a String"
fromEnvelope :: (OpenUnion es -> a) -> Envelope es a -> a Source #
Just like fromEither
but for Envelope
.
Here is an example of successfully matching:
>>>
let env = toSuccEnvelope "hello" :: Envelope '[Double, Int] String
>>>
fromEnvelope (const "not a String") env
"hello"
Here is an example of unsuccessfully matching:
>>>
let double = 3.5 :: Double
>>>
let env' = toErrEnvelope double :: Envelope '[Double, Int] String
>>>
fromEnvelope (const "not a String") env'
"not a String"
fromEnvelopeOr :: Envelope es a -> (OpenUnion es -> a) -> a Source #
Flipped version of fromEnvelope
.
fromEnvelopeM :: Applicative m => (OpenUnion es -> m a) -> Envelope es a -> m a Source #
Lifted version of fromEnvelope
.
fromEnvelopeOrM :: Applicative m => Envelope es a -> (OpenUnion es -> m a) -> m a Source #
Flipped version of fromEnvelopeM
.
errEnvelopeMatch :: forall e es a. IsMember e es => Envelope es a -> Maybe e Source #
Pull out a specific e
from an ErrEnvelope
.
Successfully pull out an e
:
>>>
let double = 3.5 :: Double
>>>
let env = toErrEnvelope double :: Envelope '[Double] ()
>>>
errEnvelopeMatch env :: Maybe Double
Just 3.5
Unsuccessfully pull out an e
:
>>>
let env' = toSuccEnvelope () :: Envelope '[Double] ()
>>>
errEnvelopeMatch env' :: Maybe Double
Nothing>>>
let env'' = toErrEnvelope 'c' :: Envelope '[Double, Char] ()
>>>
errEnvelopeMatch env'' :: Maybe Double
Nothing
catchesEnvelope :: forall tuple es a x. ToOpenProduct tuple (ReturnX x es) => tuple -> (a -> x) -> Envelope es a -> x Source #
An alternate case anaylsis for an Envelope
. This method uses a tuple
containing handlers for each potential value of the Envelope
. This is
somewhat similar to the catches
function.
Here is an example of handling an SuccEnvelope
with two possible error values.
Notice that a normal tuple is used:
>>>
let env = toSuccEnvelope 2.0 :: Envelope '[Int, String] Double
>>>
let intHandler = (\int -> show int) :: Int -> String
>>>
let strHandler = (\str -> str) :: String -> String
>>>
let succHandler = (\dbl -> "got a double") :: Double -> String
>>>
catchesEnvelope (intHandler, strHandler) succHandler env :: 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 = toErrEnvelope (3 :: Int) :: Envelope '[Int, String] Double
>>>
let intHandler = (\int -> show int) :: Int -> String
>>>
let strHandler = (\str -> str) :: String -> String
>>>
let succHandler = (\dbl -> "got a double") :: Double -> String
>>>
catchesEnvelope (intHandler, strHandler) succHandler env :: String
"3"
Given an Envelope
like
, the type of
Envelope
'[Int
, String
] Double
catchesEnvelope
becomes the following:
catchesEnvelope
:: (Int
-> x,String
-> x) -> (Double
-> x) ->Envelope
'[Int
,String
]Double
-> 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 = toErrEnvelope ("hi" :: String) :: Envelope '[Int, String, Char] Double
>>>
let intHandler = (\int -> show int) :: Int -> String
>>>
let strHandler = (\str -> str) :: String -> String
>>>
let chrHandler = (\chr -> [chr]) :: Char -> String
>>>
let succHandler = (\dbl -> "got a double") :: Double -> String
>>>
catchesEnvelope (intHandler, strHandler, chrHandler) succHandler env :: String
"hi"
Given an Envelope
like
,
the type of Envelope
'[Int
, String
, Char
] Double
catchesEnvelope
becomes the following:
catchesEnvelope
:: (Int
-> x,String
-> x,Char
-> x) -> (Double
-> x) ->Envelope
'[Int
,String
,Char
]Double
-> x
Here is an example of handling an ErrEnvelope
with only one possible error value.
Notice that a normal handler is used (not a tuple):
>>>
let env = toErrEnvelope (3 :: Int) :: Envelope '[Int] Double
>>>
let intHandler = (\int -> show int) :: Int -> String
>>>
let succHandler = (\dbl -> "got a double") :: Double -> String
>>>
catchesEnvelope intHandler succHandler env :: String
"3"
Given an Envelope
like
, the type of
Envelope
'[Int
] Double
catchesEnvelope
becomes the following:
catchesEnvelope
:: (Int
-> x) -> (Double
-> x) ->Envelope
'[Int
]Double
-> x
When working with an Envelope
with a large number of possible error types,
it can be easier to use catchesEnvelope
than envelope
.
Optics
_SuccEnvelope :: Prism (Envelope es a) (Envelope es b) a b Source #
Lens-compatible Prism
to pull out an a
from a SuccEnvelope
.
Use _SuccEnvelope
to construct an Envelope
:
>>>
review _SuccEnvelope "hello" :: Envelope '[Double] String
SuccEnvelope "hello"
Use _SuccEnvelope
to try to destruct an Envelope
into an a
:
>>>
let env = toSuccEnvelope "hello" :: Envelope '[Double] String
>>>
preview _SuccEnvelope env :: Maybe String
Just "hello"
Use _SuccEnvelope
to try to destruct a 'Envelope into an a
(unsuccessfully):
>>>
let double = 3.5 :: Double
>>>
let env' = toErrEnvelope double :: Envelope '[Double] String
>>>
preview _SuccEnvelope env' :: Maybe String
Nothing
_ErrEnvelope :: Prism (Envelope es a) (Envelope es' a) (OpenUnion es) (OpenUnion es') Source #
Lens-compatible Prism
to pull out an
from a
OpenUnion
esErrEnvelope
.
Use _ErrEnvelope
to construct an Envelope
:
>>>
let string = "hello" :: String
>>>
review _ErrEnvelope (openUnionLift string) :: Envelope '[String] Double
ErrEnvelope (Identity "hello")
Use _ErrEnvelope
to try to destruct an Envelope
into an
:OpenUnion
es
>>>
let double = 3.5 :: Double
>>>
let env = toErrEnvelope double :: Envelope '[Double] ()
>>>
preview _ErrEnvelope env :: Maybe (OpenUnion '[Double])
Just (Identity 3.5)
Use _ErrEnvelope
to try to destruct a 'Envelope into an
(unsuccessfully):OpenUnion
es
>>>
let env' = toSuccEnvelope () :: Envelope '[Double] ()
>>>
preview _ErrEnvelope env' :: Maybe (OpenUnion '[Double])
Nothing
Most users will not use _ErrEnvelope
, but instead _ErrEnvelopeErr
.
_ErrEnvelopeErr :: forall e es a. IsMember e es => Prism' (Envelope es a) e Source #
Lens-compatible Prism
to pull out a specific e
from an ErrEnvelope
.
Use _ErrEnvelopeErr
to construct an Envelope
:
>>>
let string = "hello" :: String
>>>
review _ErrEnvelopeErr string :: Envelope '[String] Double
ErrEnvelope (Identity "hello")
Use _ErrEnvelopeErr
to try to destruct an Envelope
into an e
:
>>>
let double = 3.5 :: Double
>>>
let env = toErrEnvelope double :: Envelope '[Double] ()
>>>
preview _ErrEnvelopeErr env :: Maybe Double
Just 3.5
Use _ErrEnvelopeErr
to try to destruct a 'Envelope into an
e
(unsuccessfully):
>>>
let env' = toSuccEnvelope () :: Envelope '[Double] ()
>>>
preview _ErrEnvelopeErr env' :: Maybe Double
Nothing>>>
let env'' = toErrEnvelope 'c' :: Envelope '[Double, Char] ()
>>>
preview _ErrEnvelopeErr env'' :: Maybe Double
Nothing
Most users will use _ErrEnvelopeErr
instead of _ErrEnvelope
.
Either
isoEnvelopeEither :: Iso (Envelope es a) (Envelope fs b) (Either (OpenUnion es) a) (Either (OpenUnion fs) b) Source #
Setup code for doctests
>>>
:set -XDataKinds
>>>
:set -XTypeOperators
>>>
import Control.Lens (preview, review)
>>>
import Data.Aeson (encode)
>>>
import Data.ByteString.Lazy.Char8 (hPutStrLn)
>>>
import Data.Text (Text)
>>>
import System.IO (stdout)
>>>
import Text.Read (readMaybe)
>>>
let putByteStrLn = hPutStrLn stdout