content: -- | A 'HyperType' is a type parameterized by a hypertype.
  --
  -- This infinite definition is expressible using the 'AHyperType' 'Data.Kind.Kind' for hypertypes.
  --
  -- For more information see the [README](https://github.com/lamdu/hypertypes/blob/master/README.md).
  module Hyper.Type
      ( HyperType
      , AHyperType (..)
      , GetHyperType
      , type (#)
      , type (:#)
      , asHyper
      ) where
  
  import Data.Kind (Type)
  
  import Prelude.Compat
  
  -- | A hypertype is a type parameterized by a hypertype
  type HyperType = AHyperType -> Type
  
  -- | A 'Data.Kind.Kind' for 'HyperType's
  newtype AHyperType = AHyperType HyperType
  
  -- | A type-level getter for the type constructor encoded in 'AHyperType'.
  --
  -- Notes:
  --
  -- * If @DataKinds@ supported lifting field getters this would had been replaced with the type's getter.
  -- * 'GetHyperType' is injective, but due to no support for constrained type families,
  --   [that's not expressible at the moment](https://ghc.haskell.org/trac/ghc/ticket/15691).
  -- * Because 'GetHyperType' can't declared as bijective, uses of it may restrict inference.
  --   In those cases wrapping terms with the 'asHyper' helper assists Haskell's type inference
  --   as if Haskell knew that 'GetHyperType' was bijective.
  type family GetHyperType h where
      GetHyperType ('AHyperType t) = t
  
  -- | A type synonym to express nested-HKD structures
  type h # p = (h ('AHyperType p) :: Type)
  
  -- | A type synonym to express child nodes in nested-HKDs
  type h :# p = GetHyperType h # p
  
  -- | An 'id' variant which tells the type checker that its argument is a hypertype.
  --
  -- See the notes for 'GetHyperType' which expand on why this might be used.
  --
  -- Note that 'asHyper' may often be used during development to assist the inference of incomplete code,
  -- but removed once the code is complete.
  asHyper :: h # p -> h # p
  asHyper = id
  