content: module Polysemy.Final.More where
  
  import Polysemy
  import Polysemy.Internal
  import Polysemy.Internal.Union
  import Polysemy.Final
  
  ------------------------------------------------------------------------------
  -- | Run a @'Final' ('Sem' r)@ effect if the remaining effect stack is @r@.
  --
  -- This is sometimes useful for interpreters that make use of
  -- 'reinterpret', 'raiseUnder', or any of their friends.
  runFinalSem :: Sem (Final (Sem r) ': r) a -> Sem r a
  runFinalSem = usingSem $ \u -> case decomp u of
    Right (Weaving (WithWeavingToFinal wav) s wv ex ins) ->
      ex <$> wav s (runFinalSem . wv) ins
    Left g -> liftSem (hoist runFinalSem g)
  {-# INLINE runFinalSem #-}
  
  ------------------------------------------------------------------------------
  -- | Run a @'Final' m@ effect by providing an explicit lowering function.
  --
  -- /Beware/: The lowering function may be invoked multiple times, so
  -- __don't do any initialization work inside the lowering function__:
  -- it will be duplicated.
  lowerFinal :: Member (Embed m) r
             => (forall x. Sem r x -> m x)
             -> Sem (Final m ': r) a
             -> Sem r a
  -- TODO(KingoftheHomeless): Write everything out for efficiency?
  lowerFinal f = runFinalSem . finalToFinal embed f . raiseUnder
  {-# INLINE lowerFinal #-}
  