packages feed

effectful-0.0.0.0: src/Effectful/Class/Writer.hs

{-# LANGUAGE UndecidableInstances #-}
module Effectful.Class.Writer where

import Control.Monad.Trans.Class
import Control.Monad.Trans.Control

import Effectful.Internal.Has
import Effectful.Internal.Monad
import qualified Effectful.Writer as W

-- | Compatiblity layer for a transition period from MTL-style effect handling
-- to 'Effective.Eff'.
class Monad m => MonadWriter w m where
  {-# MINIMAL (writer | tell), listen #-}

  writer :: (a, w) -> m a
  writer (a, w) = do
    tell w
    pure a

  tell :: w -> m ()
  tell w = writer ((), w)

  listen :: m a -> m (a, w)

-- | Generic, overlappable instance.
instance {-# OVERLAPPABLE #-}
  ( MonadWriter w m
  , MonadTransControl t
  , Monad (t m)
  ) => MonadWriter w (t m) where
  writer   = lift . writer
  tell     = lift . tell
  listen m = do
    (stT, w) <- liftWith $ \run -> listen (run m)
    (, w) <$> restoreT (pure stT)

instance (W.Writer w :> es, Monoid w) => MonadWriter w (Eff es) where
  writer = W.writer
  tell   = W.tell
  listen = W.listen

listens :: MonadWriter w m => (w -> b) -> m a -> m (a, b)
listens f m = do
  (a, w) <- listen m
  pure (a, f w)