HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulegrpc-spec-1.0.0Haskell2010

Network.GRPC.Spec.Util.HKD

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
  • 3 types
  • 3 classes
  • 4 values
  • Packagegrpc-spec-1.0.0
  • Exports11
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceHKD.hs

Definition

3 declarations
familytype family HKD (f :: Type -> Type) x
#

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.

Instances2HKD
  • type HKD Undecorated x = xDefined in grpc-spec-1.0.0 · Network.GRPC.Spec.Util.HKD
  • type HKD (DecoratedWith f) x = f xDefined in grpc-spec-1.0.0 · Network.GRPC.Spec.Util.HKD
datadata DecoratedWith (f :: Type -> Type) x
#

Marker for fields decorated with type constructor f

HKD (DecoratedWith f) x is equivalent to (f x). See HKD for details.

Instances10ValidDecoration, Eq, Show, HKD, …
datadata Undecorated x
#

Marker for undecorated fields

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

Instances18Eq, Show, Generic, ValidDecoration, Rep, HKD, …

Dealing with HKD records

4 declarations
classclass Coerce (t :: (Type -> Type) -> Type) where
#

Witness the isomorphism between Undecorated and DecoratedWith Identity.

Methods

  • undecorate :: t (DecoratedWith Identity) -> t Undecorated

    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)

    Introduce trivial decoration

    See undecorate for discussion of the validity of the default definitino.

Instances4Coerce
classclass Coerce t => Traversable (t :: (Type -> Type) -> Type) where
#

Higher-kinded equivalent of Traversable

Methods

Instances4Traversable

Dealing with HKD fields

2 declarations
classclass ValidDecoration (c :: (Type -> Type) -> Constraint) (f :: Type -> Type) where
#

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

Instances2ValidDecoration
valuepure :: ValidDecoration Applicative f => Proxy f -> a -> HKD f a
#

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

2 declarations