{-# LANGUAGE AllowAmbiguousTypes         #-}
{-# LANGUAGE ConstraintKinds             #-}
module Polysemy.ConstraintAbsorber
  ( 
    absorbWithSem
    
  , Reifies
  , (:-) (Sub)
  , Dict (Dict)
  , reflect
  , Proxy (Proxy)
  ) where
import           Data.Constraint (Dict(Dict), (:-)(Sub), (\\))
import qualified Data.Constraint as C
import qualified Data.Constraint.Unsafe as C
import           Data.Kind (Type, Constraint)
import           Data.Proxy (Proxy (..))
import           Data.Reflection (Reifies, reflect)
import qualified Data.Reflection as R
import           Polysemy
absorbWithSem
    :: forall 
              (p :: (Type -> Type) -> Constraint)
              
              (x :: (Type -> Type) -> Type -> Type -> Type)
              d r a
     . d  
    -> (forall s. R.Reifies s d :- p (x (Sem r) s))  
    -> (p (Sem r) => Sem r a)
    -> Sem r a
absorbWithSem d i m =  R.reify d $ \(_ :: Proxy (s :: Type)) -> m \\ C.trans
  (C.unsafeCoerceConstraint :: ((p (x m s) :- p m))) i
{-# INLINEABLE absorbWithSem #-}