grpc-spec
Safe HaskellNone
LanguageHaskell2010

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

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 to x. This avoids the overhead mentioned above.
  • DecoratedWith f, for some f: HKD (DecoratedWith f) x is equal to f 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

Instances details
type HKD Undecorated x Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

type HKD Undecorated x = x
type HKD (DecoratedWith f) x Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

type HKD (DecoratedWith f) x = f x

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

Instances details
c f => ValidDecoration c (DecoratedWith f) Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

Methods

validDecoration :: IsValidDecoration c (DecoratedWith f)

Show e => Show (RequestHeaders' e) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

Show e => Show (ProperTrailers_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Show e => Show (ResponseHeaders_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Show e => Show (TrailersOnly_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq e => Eq (RequestHeaders' e) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

Eq e => Eq (ProperTrailers_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq e => Eq (ResponseHeaders_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq e => Eq (TrailersOnly_ (Checked e)) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type HKD (DecoratedWith f) x Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

type HKD (DecoratedWith f) x = f x

data Undecorated x Source #

Marker for undecorated fields

HKD Undecorated x is equivalent to simply x. See HKD for details.

Instances

Instances details
Generic RequestHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

Associated Types

type Rep (RequestHeaders_ Undecorated) 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

type Rep (RequestHeaders_ Undecorated) = D1 ('MetaData "RequestHeaders_" "Network.GRPC.Spec.Headers.Request" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "RequestHeaders" 'PrefixI 'True) (((S1 ('MetaSel ('Just "requestTimeout") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Timeout))) :*: S1 ('MetaSel ('Just "requestCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe CompressionId)))) :*: (S1 ('MetaSel ('Just "requestAcceptCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe (NonEmpty CompressionId)))) :*: (S1 ('MetaSel ('Just "requestContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: S1 ('MetaSel ('Just "requestMessageType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe MessageType)))))) :*: ((S1 ('MetaSel ('Just "requestUserAgent") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ByteString))) :*: (S1 ('MetaSel ('Just "requestIncludeTE") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated Bool)) :*: S1 ('MetaSel ('Just "requestTraceContext") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe TraceContext))))) :*: (S1 ('MetaSel ('Just "requestPreviousRpcAttempts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Int))) :*: (S1 ('MetaSel ('Just "requestMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "requestUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ())))))))
Generic ProperTrailers Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Associated Types

type Rep (ProperTrailers_ Undecorated) 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (ProperTrailers_ Undecorated) = D1 ('MetaData "ProperTrailers_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "ProperTrailers" 'PrefixI 'True) ((S1 ('MetaSel ('Just "properTrailersGrpcStatus") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated GrpcStatus)) :*: (S1 ('MetaSel ('Just "properTrailersGrpcMessage") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Text))) :*: S1 ('MetaSel ('Just "properTrailersStatusDetails") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ByteString))))) :*: ((S1 ('MetaSel ('Just "properTrailersPushback") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Pushback))) :*: S1 ('MetaSel ('Just "properTrailersOrcaLoadReport") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe OrcaLoadReport)))) :*: (S1 ('MetaSel ('Just "properTrailersMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "properTrailersUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ()))))))
Generic ResponseHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Associated Types

type Rep (ResponseHeaders_ Undecorated) 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (ResponseHeaders_ Undecorated) = D1 ('MetaData "ResponseHeaders_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "ResponseHeaders" 'PrefixI 'True) ((S1 ('MetaSel ('Just "responseCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe CompressionId))) :*: S1 ('MetaSel ('Just "responseAcceptCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe (NonEmpty CompressionId))))) :*: (S1 ('MetaSel ('Just "responseContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: (S1 ('MetaSel ('Just "responseMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "responseUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ()))))))
Generic TrailersOnly Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Associated Types

type Rep (TrailersOnly_ Undecorated) 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (TrailersOnly_ Undecorated) = D1 ('MetaData "TrailersOnly_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "TrailersOnly" 'PrefixI 'True) (S1 ('MetaSel ('Just "trailersOnlyContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: S1 ('MetaSel ('Just "trailersOnlyProper") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (ProperTrailers_ Undecorated))))
Show RequestHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

Show ProperTrailers Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Show ResponseHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Show TrailersOnly Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq RequestHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

Eq ProperTrailers Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq ResponseHeaders Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

Eq TrailersOnly Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

ValidDecoration c Undecorated Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

Methods

validDecoration :: IsValidDecoration c Undecorated

type HKD Undecorated x Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

type HKD Undecorated x = x
type Rep (RequestHeaders_ Undecorated) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Request

type Rep (RequestHeaders_ Undecorated) = D1 ('MetaData "RequestHeaders_" "Network.GRPC.Spec.Headers.Request" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "RequestHeaders" 'PrefixI 'True) (((S1 ('MetaSel ('Just "requestTimeout") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Timeout))) :*: S1 ('MetaSel ('Just "requestCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe CompressionId)))) :*: (S1 ('MetaSel ('Just "requestAcceptCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe (NonEmpty CompressionId)))) :*: (S1 ('MetaSel ('Just "requestContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: S1 ('MetaSel ('Just "requestMessageType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe MessageType)))))) :*: ((S1 ('MetaSel ('Just "requestUserAgent") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ByteString))) :*: (S1 ('MetaSel ('Just "requestIncludeTE") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated Bool)) :*: S1 ('MetaSel ('Just "requestTraceContext") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe TraceContext))))) :*: (S1 ('MetaSel ('Just "requestPreviousRpcAttempts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Int))) :*: (S1 ('MetaSel ('Just "requestMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "requestUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ())))))))
type Rep (ProperTrailers_ Undecorated) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (ProperTrailers_ Undecorated) = D1 ('MetaData "ProperTrailers_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "ProperTrailers" 'PrefixI 'True) ((S1 ('MetaSel ('Just "properTrailersGrpcStatus") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated GrpcStatus)) :*: (S1 ('MetaSel ('Just "properTrailersGrpcMessage") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Text))) :*: S1 ('MetaSel ('Just "properTrailersStatusDetails") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ByteString))))) :*: ((S1 ('MetaSel ('Just "properTrailersPushback") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe Pushback))) :*: S1 ('MetaSel ('Just "properTrailersOrcaLoadReport") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe OrcaLoadReport)))) :*: (S1 ('MetaSel ('Just "properTrailersMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "properTrailersUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ()))))))
type Rep (ResponseHeaders_ Undecorated) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (ResponseHeaders_ Undecorated) = D1 ('MetaData "ResponseHeaders_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "ResponseHeaders" 'PrefixI 'True) ((S1 ('MetaSel ('Just "responseCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe CompressionId))) :*: S1 ('MetaSel ('Just "responseAcceptCompression") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe (NonEmpty CompressionId))))) :*: (S1 ('MetaSel ('Just "responseContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: (S1 ('MetaSel ('Just "responseMetadata") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CustomMetadataMap) :*: S1 ('MetaSel ('Just "responseUnrecognized") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated ()))))))
type Rep (TrailersOnly_ Undecorated) Source # 
Instance details

Defined in Network.GRPC.Spec.Headers.Response

type Rep (TrailersOnly_ Undecorated) = D1 ('MetaData "TrailersOnly_" "Network.GRPC.Spec.Headers.Response" "grpc-spec-1.0.0-inplace" 'False) (C1 ('MetaCons "TrailersOnly" 'PrefixI 'True) (S1 ('MetaSel ('Just "trailersOnlyContentType") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HKD Undecorated (Maybe ContentType))) :*: S1 ('MetaSel ('Just "trailersOnlyProper") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (ProperTrailers_ Undecorated))))

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.

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

Instances details
Traversable RequestHeaders_ Source # 
Instance details

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 # 
Instance details

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 # 
Instance details

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 # 
Instance details

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 any c
  • ValidDecoration c (DecoratedWith f), for any f satisfying c

Instances

Instances details
ValidDecoration c Undecorated Source # 
Instance details

Defined in Network.GRPC.Spec.Util.HKD

Methods

validDecoration :: IsValidDecoration c Undecorated

c f => ValidDecoration c (DecoratedWith f) Source # 
Instance details

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.