1 {-# LANGUAGE ConstraintKinds #-}
 
   2 {-# LANGUAGE PolyKinds #-}
 
   3 module Language.Symantic.Typing.Family where
 
   5 import Control.Applicative ((<|>))
 
   7 import Data.String (IsString(..))
 
   9 import Language.Symantic.Parsing
 
  10 import Language.Symantic.Typing.Kind
 
  11 import Language.Symantic.Typing.Type
 
  13 -- * Type family 'TyFam'
 
  14 -- | Apply the /type family/ selected by @fam@
 
  15 -- to a list of types (within a 'Proxy').
 
  16 type family TyFam fam (hs::[*]) :: *
 
  18 -- * Type 'Proj_TyFam'
 
  19 -- | Convenient type synonym wrapping 'Proj_TyFamR'
 
  20 -- to initiate its recursion.
 
  21 type Proj_TyFam cs = Proj_TyFamR cs cs
 
  23 -- | Project the 'Constraint' indexed by the given 'Type'
 
  24 -- onto its proof, captured by 'Dict' when it holds.
 
  26  :: forall fam src cs hs.
 
  28  => fam -> Types src cs hs
 
  29  -> Maybe (Type src cs (TyFam fam hs))
 
  30 proj_TyFam = proj_TyFamR (Proxy @cs)
 
  32 -- ** Class 'Proj_TyFamR'
 
  33 -- | Intermediate type class to construct an instance of 'Proj_TyFam'
 
  34 -- from many instances of 'Proj_TyFamC', one for each item of @cs@.
 
  36 -- * @cs@: starting  list of /type constants/.
 
  37 -- * @rs@: remaining list of /type constants/.
 
  38 class Proj_TyFamR (cs::[*]) (rs::[*]) fam where
 
  40          :: Proxy rs -> fam -> Types src cs hs
 
  41          -> Maybe (Type src cs (TyFam fam hs))
 
  42         proj_TyFamR _rs _fam _ty = Nothing
 
  44 -- | Test whether @c@ handles the work of 'Proj_TyFam' or not,
 
  45 -- or recurse on @rs@, preserving the starting list of /type constants/.
 
  47  ( Proj_TyFamC cs    fam c
 
  48  , Proj_TyFamR cs rs fam
 
  49  ) => Proj_TyFamR cs (Proxy c ': rs) fam where
 
  50         proj_TyFamR _rs fam typ =
 
  51                 proj_TyFamC (Proxy @c)  fam typ <|>
 
  52                 proj_TyFamR (Proxy @rs) fam typ
 
  53 -- | End the recursion.
 
  54 instance Proj_TyFamR cs '[] fam
 
  56 -- ** Class 'Proj_TyFamC'
 
  57 -- | Handle the work of 'Proj_TyFam' for a given /type family/ @fam@ and /type constant/ @c@,
 
  58 -- that is: maybe it handles the given /type family/,
 
  59 -- and if so, maybe the /type family/ has an instance for the given 'Type'.
 
  60 class Proj_TyFamC cs fam (c::kc) where
 
  62          :: Proxy c -> fam -> Types src cs hs
 
  63          -> Maybe (Type src cs (TyFam fam hs))
 
  64         proj_TyFamC _c _fam _ty = Nothing
 
  67  :: ( Inj_Error (Con_Type src cs) err
 
  72  -> (Type src cs (TyFam fam hs) -> Either err ret)
 
  75         case proj_TyFam (unAt fam) tys of
 
  77          Nothing -> Left $ inj_Error $
 
  79                  (fromString . show <$> fam)