A software engineer website

Polysemy: Opaque

Gautier DI FOLCO May 24, 2023 [Haskell] #haskell #polysemy #design #effects systems

With Polysemy 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.