content: {-# LANGUAGE KindSignatures #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE TypeInType #-}
  
  module Capability.TypeOf where
  
  import Data.Kind (Type)
  
  -- | Type family associating a tag to the corresponding type. It is intended to
  -- simplify constraint declarations, by removing the need to redundantly specify
  -- the type associated to a tag.
  --
  -- It is poly-kinded, which allows users to define their own kind of tags.
  -- Standard haskell types can also be used as tags by specifying the 'Type' kind
  -- when defining the type family instance.
  --
  -- Defining 'TypeOf' instances for 'GHC.TypeLits.Symbol's (typelevel string
  -- literals) is discouraged. Since symbols all belong to the same global
  -- namespace, such instances could conflict with others defined in external
  -- libraries. More generally, as for typeclasses, 'TypeOf' instances should
  -- always be defined in the same module as the tag type to prevent issues due to
  -- orphan instances.
  --
  -- Example:
  --
  -- @
  --     import Capability.Reader
  --
  --     data Foo
  --     data Bar
  --     type instance TypeOf Type Foo = Int
  --     type instance TypeOf Type Bar = String
  --
  --     -- Same as: foo :: HasReader Foo Int M => …
  --     foo :: HasReader' Foo m => …
  --     foo = …
  -- @
  type family TypeOf k (s :: k) :: Type
  