Move effect to top of effect stack - Polysemy

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

indiscrete-void

I'm trying to implement something like this but don't know how to do it, my every attempt leads to dead end

toTop :: (Member e r') => Sem (Append r' r) a -> Sem (e ': r) a
toTop = _

I need it in few places, first to use embedToFinal here

scopedProcToIOFinal :: (Member (Final IO) r, Member (Embed IO) r) => InterpreterFor (Scoped ProcessParams Process) r
scopedProcToIOFinal = embedToFina @IO . runScopedNew go
  where
    go param = procParamsToIOFinal param . runBundle

which currently results in dire

     Couldn't match type r with Embed IO : r
      Expected: Sem (Scoped ProcessParams Process : r) a
                -> Sem (Embed IO : r) a
        Actual: Sem (Scoped ProcessParams Process : r) a -> Sem r a
      r is a rigid type variable bound by
        the type signature for:
          scopedProcToIOFinal :: forall (r :: EffectRow).
                                 Member (Final IO) r =>
                                 InterpreterFor (Scoped ProcessParams Process) r
        at common/Polysemy/Process.hs:48:1-95
     In the second argument of (.), namely runScopedNew go
      In the expression: embedToFinal @IO . runScopedNew go
      In an equation for scopedProcToIOFinal:
          scopedProcToIOFinal
            = embedToFinal @IO . runScopedNew go
            where
                go param = procParamsToIOFinal param . runBundle
     Relevant bindings include
        scopedProcToIOFinal :: Sem (Scoped ProcessParams Process : r) a
                               -> Sem r a
          (bound at common/Polysemy/Process.hs:49:1)
   |
49 | scopedProcToIOFinal = embedToFinal @IO . runScopedNew go

Which I can work around by carrying Member (Embed IO) to concrete effect stack in main although it doesn't feel right

And most importantly

type ProcessEffects :: [Effect]
type ProcessEffects = ByteOutput : Tagged 'StandardStream ByteInput : Tagged 'ErrorStream ByteInput : Wait : '[]

type Process :: Effect
type Process = Bundle ProcessEffects

bundleProcEffects :: (Member Process r) => InterpretersFor ProcessEffects r
bundleProcEffects =
  sendBundle @Wait @ProcessEffects
    . sendBundle @(Tagged 'ErrorStream ByteInput) @ProcessEffects
    . sendBundle @(Tagged 'StandardStream ByteInput) @ProcessEffects
    . sendBundle @ByteOutput @ProcessEffects

exec :: (Member (Scoped ProcessParams Process) r) => ProcessParams -> Sem (Append ProcessEffects r) a -> Sem r a
exec params sem = scoped @_ @Process params $ bundleProcEffects sem

which results in this error that I can't even workaround

     Couldn't match type r with Process : r
      Expected: Sem (Append ProcessEffects (Process : r)) a
        Actual: Sem (Append ProcessEffects r) a
      r is a rigid type variable bound by
        the type signature for:
          exec :: forall (r :: EffectRow) a.
                  Member (Scoped ProcessParams Process) r =>
                  ProcessParams -> Sem (Append ProcessEffects r) a -> Sem r a
        at common/Polysemy/Process.hs:43:1-112
     In the first argument of bundleProcEffects, namely sem
      In the second argument of ($), namely bundleProcEffects sem
      In the expression:
        scoped @_ @Process params $ bundleProcEffects sem
     Relevant bindings include
        sem :: Sem (Append ProcessEffects r) a
          (bound at common/Polysemy/Process.hs:44:13)
        exec :: ProcessParams -> Sem (Append ProcessEffects r) a -> Sem r a
          (bound at common/Polysemy/Process.hs:44:1)
   |
44 | exec params sem = scoped @_ @Process params $ bundleProcEffects sem
   |                                                                 ^^^
indiscrete-void

As it often happens: I couldn't solve the issue, post to find some help and solve it like 10 minutes after trying to do it for many days ahahah

Here's solution for reference so people can find it by title:

exec :: (Member (Scoped ProcessParams Process) r) => ProcessParams -> InterpretersFor ProcessEffects r
exec params = scoped @_ @Process params . bundleProcEffects . insertAt @4 @'[Process]
scopedProcToIOFinal :: (Member (Final IO) r) => InterpreterFor (Scoped ProcessParams Process) r
scopedProcToIOFinal = embedToFinal @IO . runScopedNew go . raiseUnder

(IDK if general toTop exists, I haven't found it)

Torsten Schmits

a more general variant of these combinators is subsume_, but it's a bit of a gamble.

as a side note: are you aware of polysemy-process? If so, what are you missing from it?