content: -- | The auxiliary effect 'Opaque' used by interpreters of 'Polysemy.Scoped.Scoped'
  module Polysemy.Opaque (
    -- * Effect
    Opaque(..),
  
    -- * Interpreters
    toOpaque,
    fromOpaque,
    ) where
  
  import Polysemy
  
  -- | An effect newtype meant to be used to wrap polymorphic effect variables to
  -- prevent them from jamming up resolution of 'Polysemy.Member'.
  -- For example, consider:
  --
  -- @
  -- badPut :: 'Sem' (e ': 'Polysemy.State.State' () ': r) ()
  -- badPut = 'Polysemy.State.put' () -- error
  -- @
  --
  -- This fails to compile. This is because @e@ /could/ be
  -- @'Polysemy.State.State' ()@' -- in which case the 'Polysemy.State.put'
  -- should target it instead of the concretely provided
  -- @'Polysemy.State.State' ()@; as the compiler can't know for sure which effect
  -- should be targeted, the program is rejected.
  -- There are various ways to resolve this, including using 'raise' or
  -- 'Polysemy.Membership.subsumeUsing'. 'Opaque' provides another way:
  --
  -- @
  -- okPut :: 'Sem' (e ': 'Polysemy.State.State' () ': r) ()
  -- okPut = 'fromOpaque' ('Polysemy.State.put' ()) -- OK
  -- @
  --
  -- 'Opaque' is most useful as a tool for library writers, in the case where some
  -- function of the library requires the user to work with an effect stack
  -- containing some polymorphic effect variables. By wrapping the polymorphic
  -- effect variables using 'Opaque', users of the function can use effects as
  -- normal, without having to use 'raise' or 'Polysemy.Membership.subsumeUsing'
  -- in order to have 'Polysemy.Member' resolve. The various interpreters of
  -- 'Polysemy.Scoped.Scoped' are examples of such usage of 'Opaque'.
  --
  -- @since 1.9.0.0
  newtype Opaque (e :: Effect) m a = Opaque (e m a)
  
  -- | Wrap 'Opaque' around the top effect of the effect stack
  toOpaque :: Sem (e ': r) a -> Sem (Opaque e ': r) a
  toOpaque = rewrite Opaque
  {-# INLINE toOpaque #-}
  
  -- | Unwrap 'Opaque' around the top effect of the effect stack
  fromOpaque :: Sem (Opaque e ': r) a -> Sem (e ': r) a
  fromOpaque = rewrite (\(Opaque e) -> e)
  {-# INLINE fromOpaque #-}
  