packages feed

effectful-core-2.7.1.0: src/Effectful/Output/Static/Action.hs

{-# LANGUAGE ImplicitParams #-}
-- | Support for feeding values of a particular type to a monadic action.
--
-- @since 2.7.0.0
module Effectful.Output.Static.Action
  ( -- * Effect
    Output

    -- ** Handlers
  , runOutput

    -- ** Operations
  , output
  ) where

import Data.Kind
import GHC.Stack

import Effectful
import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Internal.Utils

-- | Provide the ability to feed values of type @o@ to a monadic action.
data Output (o :: Type) :: Effect

type instance DispatchOf (Output o) = Static NoSideEffects

-- | Wrapper to prevent a space leak on reconstruction of 'Output' in
-- 'relinkOutput' (see https://gitlab.haskell.org/ghc/ghc/-/issues/25520).
newtype OutputImpl o es where
  OutputImpl :: (HasCallStack => o -> Eff es ()) -> OutputImpl o es

data instance StaticRep (Output o) where
  Output
    :: !(Env actionEs)
    -> !(OutputImpl o actionEs)
    -> StaticRep (Output o)

-- | Run the 'Output' effect with the given action for receiving values.
runOutput
  :: forall o es a
   . HasCallStack
  => (HasCallStack => o -> Eff es ())
  -- ^ The action for receiving values.
  -> Eff (Output o : es) a
  -> Eff es a
runOutput outputAction action = unsafeEff $ \es -> do
  inlineBracket
    (consEnv (Output es outputImpl) relinkOutput es)
    unconsEnv
    (unEff action)
  where
    outputImpl = OutputImpl $ let ?callStack = thawCallStack ?callStack in outputAction

-- | Feed the value to the underlying monadic action.
output
  :: (HasCallStack, Output o :> es)
  => o -- ^ The value.
  -> Eff es ()
output !o = unsafeEff $ \es -> do
  Output actionEs (OutputImpl outputAction) <- getEnv es
  -- Corresponds to thawCallStack in runOutput.
  (`unEff` actionEs) $ withFrozenCallStack outputAction o

----------------------------------------
-- Helpers

relinkOutput :: Relinker StaticRep (Output o)
relinkOutput = Relinker $ \relink (Output actionEs outputAction) -> do
  newActionEs <- relink actionEs
  pure $ Output newActionEs outputAction