packages feed

disco-0.2: src/Polysemy/ConstraintAbsorber.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}

-- This module was copied from polysemy-zoo:
-- https://hackage.haskell.org/package/polysemy-zoo-0.8.2.0/docs/src/Polysemy.ConstraintAbsorber.html

module Polysemy.ConstraintAbsorber (
  -- * Absorb builder
  absorbWithSem,

  -- * Re-exports
  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 (Constraint, Type)
import Data.Proxy (Proxy (..))
import Data.Reflection (Reifies, reflect)
import qualified Data.Reflection as R
import Polysemy

------------------------------------------------------------------------------

-- | This function can be used to locally introduce typeclass instances for
-- 'Sem'. See 'Polysemy.ConstraintAbsorber.MonadState' for an example of how to
-- use it.
absorbWithSem ::
  forall
    -- Constraint to be absorbed
    (p :: (Type -> Type) -> Constraint)
    -- Wrapper to avoid orphan instances
    (x :: (Type -> Type) -> Type -> Type -> Type)
    d
    r
    a.
  -- | Reified dictionary
  d ->
  -- | This parameter should always be @'Sub' 'Dict'@
  (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 #-}