Polysemy: Opaque

With Polysemy 1.9.0.0 came the Opaque effect.

It's defined as follows:

newtype Opaque (e :: Effect) m a where
  Opaque :: forall e m a. e m a -> Opaque e m a

If you recall, it looks like Tagged

newtype Tagged k e m a where
  Tagged :: forall k e m a. e m a -> Tagged k e m a

It just lacks the tag name (a phantom type).

It comes with two functions:

toOpaque :: Sem (e ': r) a -> Sem (Opaque e ': r) a
fromOpaque :: Sem (Opaque e ': r) a -> Sem (e ': r) a

It's particularly useful when you have type variables as effects:

wrong :: Sem (e ': Trace ': r) ()
wrong = trace "Wrong"

will produce:

Overlapping instances for Member Trace (e : Trace : r)
        arising from a use of ‘trace’
      Matching instances:
        two instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
      (The choice depends on the instantiation of ‘e, r’
       To pick the first instance above, use IncoherentInstances
       when compiling the other instance declarations)
In the expression: trace "Wrong"
      In an equation for ‘wrong’: wrong = trace "Wrong"
  |
  | wrong = trace "Wrong"
  |

While, this works:

ok :: Sem (e ': Trace ': r) ()
ok = fromOpaque $ trace "Works"

See the full the code here.