{-#LANGUAGE DataKinds,TypeFamilies#-} --import Colog.Core.Action() import Data.ByteString (ByteString) import Data.ByteString qualified as BS import Data.Kind import Data.Text (Text) import Data.Text.Encoding (encodeUtf8) import Effectful import Effectful.Dispatch.Static import Effectful.Internal.Env (Env, Relinker (..), consEnv, unconsEnv) import Effectful.Internal.Utils (inlineBracket) import Effectful.Writer.Dynamic (Writer, tell) -- Test Module Imports import Data.Text(pack) import Test.QuickCheck import Effectful import Effectful.Writer.Dynamic import Effectful.Labeled import Effectful.Provider -- From Colog.Core.Action() newtype LogAction m msg = LogAction { unLogAction :: msg -> m () } -- | Provides the ability to log with an implicit 'LogEff' type Log :: Type -> Effect data Log msg m a type instance DispatchOf (Log msg) = Static NoSideEffects data instance StaticRep (Log msg) where MkLog :: forall localEs msg. !(Env localEs) -> !(LogEff localEs msg) -> StaticRep (Log msg) -- | 'LogAction' limited to the 'Eff' monad type LogEff es msg = LogAction (Eff es) msg unLogEff :: forall es msg. LogEff es msg -> msg -> Env es -> IO () unLogEff le = unEff . unLogAction le relinkLog :: forall msg. Relinker StaticRep (Log msg) relinkLog = Relinker $ \relink (MkLog localEs act) -> do newLocalEs <- relink localEs pure $ MkLog newLocalEs act -- | runs the 'Log' effect using the provided action runLogAction :: forall es msg a. LogEff es msg -> Eff (Log msg : es) a -> Eff es a runLogAction logAct act = unsafeEff $ \env -> do inlineBracket (consEnv (MkLog env logAct) relinkLog env) unconsEnv (\es -> unEff act es) -- | logs a message using the implicit 'LogEff' logMsg :: forall msg es. (Log msg :> es) => msg -> Eff es () logMsg message = do MkLog env act <- getStaticRep -- TODO: is this safe? unsafeEff_ $ unLogEff act message env -- | 'LogEff' that delegates to a dynamic 'Writer' effect tellLogEff :: forall es msg. (Writer msg :> es) => LogEff es msg tellLogEff = LogAction tell instance Arbitrary Text where arbitrary = fmap pack arbitrary prop_providerLogShared :: Text -> Property prop_providerLogShared msg = property @Property . runPureEff . fmap ((=== msg) . snd) . runWriterShared @Text . runProvider_ (runLogAction) $ provideWith_ (tellLogEff ) $ listen $ logMsg @Text msg