{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

{- |
 Module      :  Control.Monad.Tell.Class
 Copyright   :  (C) 2021 Isaac Elliott
 License     :  BSD-3 (see the file LICENSE)
 Maintainer  :  Isaac Elliott <isaace71295@gmail.com>
-}
module Control.Monad.Tell.Class (MonadTell (..), WrappedMonadWriter (..)) where

import Control.Monad.Trans.Accum (AccumT)
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Trans.Cont (ContT)
import Control.Monad.Trans.Identity (IdentityT)
import Control.Monad.Trans.Maybe (MaybeT)
import qualified Control.Monad.Trans.RWS.CPS as CPS (RWST)
import qualified Control.Monad.Trans.RWS.CPS as RWS.CPS
import qualified Control.Monad.Trans.RWS.Lazy as Lazy
import qualified Control.Monad.Trans.RWS.Strict as Strict
import Control.Monad.Trans.Reader (ReaderT)
import Control.Monad.Trans.Select (SelectT)
import qualified Control.Monad.Trans.State.Lazy as Lazy
import qualified Control.Monad.Trans.State.Strict as Strict
import qualified Control.Monad.Trans.Writer.CPS as CPS (WriterT)
import qualified Control.Monad.Trans.Writer.CPS as Writer.CPS
import qualified Control.Monad.Trans.Writer.Lazy as Lazy
import qualified Control.Monad.Trans.Writer.Strict as Strict
import Control.Monad.Writer.Class (MonadWriter)
import qualified Control.Monad.Writer.Class as Writer.Class

{- |

== Laws

@tell mempty ≡ pure ()@

@tell (a <> b) ≡ tell a *> tell b@

== How does this relate to 'MonadWriter'?

'MonadTell' is a generalisation of 'MonadWriter'. It only provides 'tell';
a function that \'appends\' a monoidal value to some output. Morally, we have
@class 'MonadTell' w m => 'MonadWriter' w m where ...@. See 'WrappedMonadWriter'
for the witness of this.

'MonadWriter'\'s 'Control.Monad.Writer.Class.listen' and 'Control.Monad.Writer.Class.pass'
functions require the monad to hold onto
the output for an arbitrarily long time. This can cause applications to use memory
linear in the number of 'Control.Monad.Writer.tell's, when constant memory usage would suffice.

A motivating example is writing monoidal results to a file. Using 'MonadWriter'
(via a @WriterT@), you would have to accumulate the the entire output and then write it
to the file. In contrast, 'MonadTell' allows you to write each result to the file
as it's obtained, allowing the result to be freed while the rest of the program runs.
-}
class (Monoid w, Monad m) => MonadTell w m | m -> w where
  tell :: w -> m ()
  default tell :: (m ~ t n, MonadTrans t, MonadTell w n) => w -> m ()
  tell = n () -> t n ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (n () -> t n ()) -> (w -> n ()) -> w -> t n ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> n ()
forall w (m :: * -> *). MonadTell w m => w -> m ()
tell

instance (Monoid w, Monad m) => MonadTell w (Strict.WriterT w m) where
  tell :: w -> WriterT w m ()
tell = WrappedMonadWriter (WriterT w m) () -> WriterT w m ()
forall (m :: * -> *) a. WrappedMonadWriter m a -> m a
getWrappedMonadWriter (WrappedMonadWriter (WriterT w m) () -> WriterT w m ())
-> (w -> WrappedMonadWriter (WriterT w m) ())
-> w
-> WriterT w m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> WrappedMonadWriter (WriterT w m) ()
forall w (m :: * -> *). MonadTell w m => w -> m ()
tell

instance (Monoid w, Monad m) => MonadTell w (Lazy.WriterT w m) where
  tell :: w -> WriterT w m ()
tell = WrappedMonadWriter (WriterT w m) () -> WriterT w m ()
forall (m :: * -> *) a. WrappedMonadWriter m a -> m a
getWrappedMonadWriter (WrappedMonadWriter (WriterT w m) () -> WriterT w m ())
-> (w -> WrappedMonadWriter (WriterT w m) ())
-> w
-> WriterT w m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> WrappedMonadWriter (WriterT w m) ()
forall w (m :: * -> *). MonadTell w m => w -> m ()
tell

instance (Monoid w, Monad m) => MonadTell w (CPS.WriterT w m) where
  tell :: w -> WriterT w m ()
tell = w -> WriterT w m ()
forall w (m :: * -> *). (Monoid w, Monad m) => w -> WriterT w m ()
Writer.CPS.tell

instance (Monoid w, Monad m) => MonadTell w (Strict.RWST r w s m) where
  tell :: w -> RWST r w s m ()
tell = WrappedMonadWriter (RWST r w s m) () -> RWST r w s m ()
forall (m :: * -> *) a. WrappedMonadWriter m a -> m a
getWrappedMonadWriter (WrappedMonadWriter (RWST r w s m) () -> RWST r w s m ())
-> (w -> WrappedMonadWriter (RWST r w s m) ())
-> w
-> RWST r w s m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> WrappedMonadWriter (RWST r w s m) ()
forall w (m :: * -> *). MonadTell w m => w -> m ()
tell

instance (Monoid w, Monad m) => MonadTell w (Lazy.RWST r w s m) where
  tell :: w -> RWST r w s m ()
tell = WrappedMonadWriter (RWST r w s m) () -> RWST r w s m ()
forall (m :: * -> *) a. WrappedMonadWriter m a -> m a
getWrappedMonadWriter (WrappedMonadWriter (RWST r w s m) () -> RWST r w s m ())
-> (w -> WrappedMonadWriter (RWST r w s m) ())
-> w
-> RWST r w s m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> WrappedMonadWriter (RWST r w s m) ()
forall w (m :: * -> *). MonadTell w m => w -> m ()
tell

instance (Monoid w, Monad m) => MonadTell w (CPS.RWST r w s m) where
  tell :: w -> RWST r w s m ()
tell = w -> RWST r w s m ()
forall w (m :: * -> *) r s.
(Monoid w, Monad m) =>
w -> RWST r w s m ()
RWS.CPS.tell

instance (MonadTell w m, Monoid s) => MonadTell w (AccumT s m)
instance MonadTell w m => MonadTell w (ContT r m)
instance MonadTell w m => MonadTell w (IdentityT m)
instance MonadTell w m => MonadTell w (MaybeT m)
instance MonadTell w m => MonadTell w (ReaderT r m)
instance MonadTell w m => MonadTell w (SelectT r m)
instance MonadTell w m => MonadTell w (Lazy.StateT s m)
instance MonadTell w m => MonadTell w (Strict.StateT s m)

-- | A proof that a 'MonadWriter' instance implies a 'MonadTell' instance.
newtype WrappedMonadWriter m a = WrappedMonadWriter {WrappedMonadWriter m a -> m a
getWrappedMonadWriter :: m a}
  deriving (a -> WrappedMonadWriter m b -> WrappedMonadWriter m a
(a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b
(forall a b.
 (a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b)
-> (forall a b.
    a -> WrappedMonadWriter m b -> WrappedMonadWriter m a)
-> Functor (WrappedMonadWriter m)
forall a b. a -> WrappedMonadWriter m b -> WrappedMonadWriter m a
forall a b.
(a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b
forall (m :: * -> *) a b.
Functor m =>
a -> WrappedMonadWriter m b -> WrappedMonadWriter m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> WrappedMonadWriter m b -> WrappedMonadWriter m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> WrappedMonadWriter m b -> WrappedMonadWriter m a
fmap :: (a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> WrappedMonadWriter m a -> WrappedMonadWriter m b
Functor, Functor (WrappedMonadWriter m)
a -> WrappedMonadWriter m a
Functor (WrappedMonadWriter m)
-> (forall a. a -> WrappedMonadWriter m a)
-> (forall a b.
    WrappedMonadWriter m (a -> b)
    -> WrappedMonadWriter m a -> WrappedMonadWriter m b)
-> (forall a b c.
    (a -> b -> c)
    -> WrappedMonadWriter m a
    -> WrappedMonadWriter m b
    -> WrappedMonadWriter m c)
-> (forall a b.
    WrappedMonadWriter m a
    -> WrappedMonadWriter m b -> WrappedMonadWriter m b)
-> (forall a b.
    WrappedMonadWriter m a
    -> WrappedMonadWriter m b -> WrappedMonadWriter m a)
-> Applicative (WrappedMonadWriter m)
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m a
WrappedMonadWriter m (a -> b)
-> WrappedMonadWriter m a -> WrappedMonadWriter m b
(a -> b -> c)
-> WrappedMonadWriter m a
-> WrappedMonadWriter m b
-> WrappedMonadWriter m c
forall a. a -> WrappedMonadWriter m a
forall a b.
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m a
forall a b.
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
forall a b.
WrappedMonadWriter m (a -> b)
-> WrappedMonadWriter m a -> WrappedMonadWriter m b
forall a b c.
(a -> b -> c)
-> WrappedMonadWriter m a
-> WrappedMonadWriter m b
-> WrappedMonadWriter m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall (m :: * -> *).
Applicative m =>
Functor (WrappedMonadWriter m)
forall (m :: * -> *) a.
Applicative m =>
a -> WrappedMonadWriter m a
forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m a
forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m (a -> b)
-> WrappedMonadWriter m a -> WrappedMonadWriter m b
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WrappedMonadWriter m a
-> WrappedMonadWriter m b
-> WrappedMonadWriter m c
<* :: WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m a
$c<* :: forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m a
*> :: WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
$c*> :: forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
liftA2 :: (a -> b -> c)
-> WrappedMonadWriter m a
-> WrappedMonadWriter m b
-> WrappedMonadWriter m c
$cliftA2 :: forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WrappedMonadWriter m a
-> WrappedMonadWriter m b
-> WrappedMonadWriter m c
<*> :: WrappedMonadWriter m (a -> b)
-> WrappedMonadWriter m a -> WrappedMonadWriter m b
$c<*> :: forall (m :: * -> *) a b.
Applicative m =>
WrappedMonadWriter m (a -> b)
-> WrappedMonadWriter m a -> WrappedMonadWriter m b
pure :: a -> WrappedMonadWriter m a
$cpure :: forall (m :: * -> *) a.
Applicative m =>
a -> WrappedMonadWriter m a
$cp1Applicative :: forall (m :: * -> *).
Applicative m =>
Functor (WrappedMonadWriter m)
Applicative, Applicative (WrappedMonadWriter m)
a -> WrappedMonadWriter m a
Applicative (WrappedMonadWriter m)
-> (forall a b.
    WrappedMonadWriter m a
    -> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b)
-> (forall a b.
    WrappedMonadWriter m a
    -> WrappedMonadWriter m b -> WrappedMonadWriter m b)
-> (forall a. a -> WrappedMonadWriter m a)
-> Monad (WrappedMonadWriter m)
WrappedMonadWriter m a
-> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
forall a. a -> WrappedMonadWriter m a
forall a b.
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
forall a b.
WrappedMonadWriter m a
-> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b
forall (m :: * -> *). Monad m => Applicative (WrappedMonadWriter m)
forall (m :: * -> *) a. Monad m => a -> WrappedMonadWriter m a
forall (m :: * -> *) a b.
Monad m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
forall (m :: * -> *) a b.
Monad m =>
WrappedMonadWriter m a
-> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> WrappedMonadWriter m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> WrappedMonadWriter m a
>> :: WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
WrappedMonadWriter m a
-> WrappedMonadWriter m b -> WrappedMonadWriter m b
>>= :: WrappedMonadWriter m a
-> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
WrappedMonadWriter m a
-> (a -> WrappedMonadWriter m b) -> WrappedMonadWriter m b
$cp1Monad :: forall (m :: * -> *). Monad m => Applicative (WrappedMonadWriter m)
Monad)

instance MonadTrans WrappedMonadWriter where
  lift :: m a -> WrappedMonadWriter m a
lift = m a -> WrappedMonadWriter m a
forall (m :: * -> *) a. m a -> WrappedMonadWriter m a
WrappedMonadWriter

instance MonadWriter w m => MonadTell w (WrappedMonadWriter m) where
  tell :: w -> WrappedMonadWriter m ()
tell = m () -> WrappedMonadWriter m ()
forall (m :: * -> *) a. m a -> WrappedMonadWriter m a
WrappedMonadWriter (m () -> WrappedMonadWriter m ())
-> (w -> m ()) -> w -> WrappedMonadWriter m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
Writer.Class.tell