Safe Haskell | None |
---|---|
Language | Haskell2010 |
Network.GRPC.Spec.Util.HKD
Description
Small module to support the higher-kinded data (HKD) pattern
This module is similar in spirit to libraries such as barbies
(and to
lesser degree hkd
), but the technical details of the approach are somewhat
different.
Intended for qualified import.
import Network.GRPC.Spec.Util.HKD (HKD, Undecorated, DecoratedWith) import Network.GRPC.Spec.Util.HKD qualified as HKD
Synopsis
- type family HKD (f :: Type -> Type) x
- data DecoratedWith (f :: Type -> Type) x
- data Undecorated x
- class Coerce (t :: (Type -> Type) -> Type) where
- undecorate :: t (DecoratedWith Identity) -> t Undecorated
- decorate :: t Undecorated -> t (DecoratedWith Identity)
- class Coerce t => Traversable (t :: (Type -> Type) -> Type) where
- traverse :: Applicative m => (forall a. f a -> m (g a)) -> t (DecoratedWith f) -> m (t (DecoratedWith g))
- sequence :: (Traversable t, Applicative m) => t (DecoratedWith m) -> m (t Undecorated)
- map :: Traversable t => (forall a. f a -> g a) -> t (DecoratedWith f) -> t (DecoratedWith g)
- class ValidDecoration (c :: (Type -> Type) -> Constraint) (f :: Type -> Type)
- pure :: forall (f :: Type -> Type) a. ValidDecoration Applicative f => Proxy f -> a -> HKD f a
- type Checked e = DecoratedWith (Either e)
- sequenceChecked :: (MonadError e m, Traversable t) => t (Checked e) -> m (t Undecorated)
Definition
type family HKD (f :: Type -> Type) x Source #
Marker for fields of HKD types
A common pattern for datatypes is to wrap every field in a type constructor:
data RequestHeaders_ f = RequestHeaders { requestTimeout :: f (Maybe Timeout) , requestCompression :: f (Maybe CompressionId) , .. }
The downside of such an approach is that if we don't need that type
constructor, we must instantiate f
to Identity
, which results in
syntactic overhead.
(See also
The Haskell Unfolder episode 14: Higher-kinded types.)
The HKD
family is designed to avoid this overhead:
data RequestHeaders_ f = RequestHeaders { requestTimeout :: HKD f (Maybe Timeout) , requestCompression :: HKD f (Maybe CompressionId) , .. }
There are then two valid choices for f
:
Undecorated
:HKD Undecorated x
is simply equal tox
. This avoids the overhead mentioned above.DecoratedWith
f
, for somef
:HKD (DecoratedWith f) x
is equal tof x
.
This explicit distinction between Undecorated
and DecoratedWith
is the
main difference between the approach in this module and other libraries that
provide similar functionality.
Instances
type HKD Undecorated x Source # | |
Defined in Network.GRPC.Spec.Util.HKD | |
type HKD (DecoratedWith f) x Source # | |
Defined in Network.GRPC.Spec.Util.HKD |
data DecoratedWith (f :: Type -> Type) x Source #
Marker for fields decorated with type constructor f
HKD (DecoratedWith f) x
is equivalent to (f x)
. See HKD
for details.
Instances
data Undecorated x Source #
Marker for undecorated fields
HKD Undecorated x
is equivalent to simply x
. See HKD
for details.
Instances
Dealing with HKD records
class Coerce (t :: (Type -> Type) -> Type) where Source #
Witness the isomorphism between Undecorated
and DecoratedWith Identity
.
Minimal complete definition
Nothing
Methods
undecorate :: t (DecoratedWith Identity) -> t Undecorated Source #
Drop decoration
NOTE: The default instance is valid only for datatypes that are morally
have a "higher order representative role"; that is, the type of every field
of t (DecoratedWith Identity)
must be representationally equal to the
corresponding type of t Undecorated
. In the typical case of
data SomeRecord f = MkSomeRecord { field1 :: HKD f a1 , field2 :: HKD f a2 .. , fieldN :: aN , .. , fieldM :: HKD f aM }
where every field either has type HKD f a
or a
(not mentioning f
at
all), this will automatically be the case.
decorate :: t Undecorated -> t (DecoratedWith Identity) Source #
Introduce trivial decoration
See undecorate
for discussion of the validity of the default definitino.
Instances
Coerce RequestHeaders_ Source # | |
Defined in Network.GRPC.Spec.Headers.Request | |
Coerce ProperTrailers_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response | |
Coerce ResponseHeaders_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response | |
Coerce TrailersOnly_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response Methods undecorate :: TrailersOnly_ (DecoratedWith Identity) -> TrailersOnly_ Undecorated Source # decorate :: TrailersOnly_ Undecorated -> TrailersOnly_ (DecoratedWith Identity) Source # |
class Coerce t => Traversable (t :: (Type -> Type) -> Type) where Source #
Higher-kinded equivalent of Traversable
Methods
traverse :: Applicative m => (forall a. f a -> m (g a)) -> t (DecoratedWith f) -> m (t (DecoratedWith g)) Source #
Instances
Traversable RequestHeaders_ Source # | |
Defined in Network.GRPC.Spec.Headers.Request Methods traverse :: Applicative m => (forall a. f a -> m (g a)) -> RequestHeaders_ (DecoratedWith f) -> m (RequestHeaders_ (DecoratedWith g)) Source # | |
Traversable ProperTrailers_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response Methods traverse :: Applicative m => (forall a. f a -> m (g a)) -> ProperTrailers_ (DecoratedWith f) -> m (ProperTrailers_ (DecoratedWith g)) Source # | |
Traversable ResponseHeaders_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response Methods traverse :: Applicative m => (forall a. f a -> m (g a)) -> ResponseHeaders_ (DecoratedWith f) -> m (ResponseHeaders_ (DecoratedWith g)) Source # | |
Traversable TrailersOnly_ Source # | |
Defined in Network.GRPC.Spec.Headers.Response Methods traverse :: Applicative m => (forall a. f a -> m (g a)) -> TrailersOnly_ (DecoratedWith f) -> m (TrailersOnly_ (DecoratedWith g)) Source # |
sequence :: (Traversable t, Applicative m) => t (DecoratedWith m) -> m (t Undecorated) Source #
Higher-kinded equivalent of sequence
map :: Traversable t => (forall a. f a -> g a) -> t (DecoratedWith f) -> t (DecoratedWith g) Source #
Higher-kinded equivalent of map
Dealing with HKD fields
class ValidDecoration (c :: (Type -> Type) -> Constraint) (f :: Type -> Type) Source #
Valid decorations
These are only two valid decorations (and new instances of this class cannot be defined):
ValidDecoration c Undecorated
, for anyc
ValidDecoration c (DecoratedWith f)
, for anyf
satisfyingc
Instances
ValidDecoration c Undecorated Source # | |
Defined in Network.GRPC.Spec.Util.HKD Methods validDecoration :: IsValidDecoration c Undecorated | |
c f => ValidDecoration c (DecoratedWith f) Source # | |
Defined in Network.GRPC.Spec.Util.HKD Methods validDecoration :: IsValidDecoration c (DecoratedWith f) |
pure :: forall (f :: Type -> Type) a. ValidDecoration Applicative f => Proxy f -> a -> HKD f a Source #
Specify field value of record with unknown decoration
You may need an additional type annotation also for a
; for example
HKD.pure (Proxy @f) Nothing
will result in an error message such as
Couldn't match expected type: HKD f (Maybe SomeConcreteType) with actual type: HKD f (Maybe a0)
This is because HKD
is a type family in two arguments (even though in an
ideal world it should be defined as a type family in one argument).
Error decorations
type Checked e = DecoratedWith (Either e) Source #
Decorate with potential errors
sequenceChecked :: (MonadError e m, Traversable t) => t (Checked e) -> m (t Undecorated) Source #
Throw all errors found in the datatype
Given a datatype decorated with potential errors, find and throw any errors; if no errors are found, return the undecorated value.