{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Type.Membership
  ( 
  Membership
  , getMemberId
  , mkMembership
  , leadership
  , nextMembership
  , testMembership
  , compareMembership
  , impossibleMembership
  , reifyMembership
  , Member
  
  , Assoc(..)
  , type (>:)
  , Lookup(..)
  , KeyOf
  , KeyIs
  , proxyKeyOf
  , stringKeyOf
  , TargetOf
  , proxyTargetOf
  , TargetIs
  , KeyTargetAre
  
  , Generate(..)
  , Forall(..)
  , ForallF
  
  , Proxy(..)
  ) where
import Data.Constraint
import Data.Proxy
import Data.String
import GHC.TypeLits
import Type.Membership.Internal
class Generate (xs :: [k]) where
  
  henumerate :: (forall x. Membership xs x -> r -> r) -> r -> r
  
  hcount :: proxy xs -> Int
  
  hgenerateList :: Applicative f
    => (forall x. Membership xs x -> f (h x)) -> f (HList h xs)
instance Generate '[] where
  henumerate _ r = r
  hcount _ = 0
  hgenerateList _ = pure HNil
instance Generate xs => Generate (x ': xs) where
  henumerate f r = f leadership $ henumerate (f . nextMembership) r
  hcount _ = 1 + hcount (Proxy :: Proxy xs)
  
  hgenerateList f = HCons <$> f leadership <*> hgenerateList (f . nextMembership)
class (ForallF c xs, Generate xs) => Forall (c :: k -> Constraint) (xs :: [k]) where
  
  henumerateFor :: proxy c -> proxy' xs -> (forall x. c x => Membership xs x -> r -> r) -> r -> r
  hgenerateListFor :: Applicative f
    => proxy c -> (forall x. c x => Membership xs x -> f (h x)) -> f (HList h xs)
instance Forall c '[] where
  henumerateFor _ _ _ r = r
  hgenerateListFor _ _ = pure HNil
instance (c x, Forall c xs) => Forall c (x ': xs) where
  henumerateFor p _ f r = f leadership $ henumerateFor p (Proxy :: Proxy xs) (f . nextMembership) r
  hgenerateListFor p f = HCons <$> f leadership <*> hgenerateListFor p (f . nextMembership)
type family ForallF (c :: k -> Constraint) (xs :: [k]) :: Constraint where
  ForallF c '[] = ()
  ForallF c (x ': xs) = (c x, Forall c xs)
type family KeyOf (kv :: Assoc k v) :: k where
  KeyOf (k ':> v) = k
proxyKeyOf :: proxy kv -> Proxy (KeyOf kv)
proxyKeyOf _ = Proxy
stringKeyOf :: (IsString a, KnownSymbol (KeyOf kv)) => proxy kv -> a
stringKeyOf = fromString . symbolVal . proxyKeyOf
{-# INLINE stringKeyOf #-}
class (pk (KeyOf kv)) => KeyIs pk kv where
instance (pk k) => KeyIs pk (k ':> v)
type family TargetOf (kv :: Assoc k v) :: v where
  TargetOf (k ':> v) = v
proxyTargetOf :: proxy kv -> Proxy (TargetOf kv)
proxyTargetOf _ = Proxy
class (pv (TargetOf kv)) => TargetIs pv kv where
instance (pv v) => TargetIs pv (k ':> v)
class (pk (KeyOf kv), pv (TargetOf kv)) => KeyTargetAre pk pv kv where
instance (pk k, pv v) => KeyTargetAre pk pv (k ':> v)