{-# LANGUAGE TypeFamilies, CPP #-}

-- | The writer monad applied to 'LaTeX' values. Useful to compose 'LaTeX' values
--   using the @do@ notation:
--
-- > anExample :: Monad m => LaTeXT m ()
-- > anExample = do
-- >   documentclass [] article
-- >   author "Daniel Monad"
-- >   title "LaTeX and do notation"
-- >   document $ do
-- >     maketitle
-- >     section "Some words"
-- >     "Using " ; texttt "do" ; " notation "
-- >     "you avoid many ocurrences of the "
-- >     texttt "(<>)" ; " operator and a lot of "
-- >     "parentheses. With the cost of a monad."
--
-- Since 'LaTeXT' is a monad transformer, you can do also:
--
-- > anotherExample :: LaTeXT IO ()
-- > anotherExample = lift (readFileTex "foo") >>= verbatim
--
-- This way, it is easy (without carrying arguments) to include IO outputs
-- in the LaTeX document, like files, times or random objects.
--
-- Another approach could be to have custom counters, label management
-- or any other user-defined feature.
--
-- Of course, you can always use the simpler interface provided by the plain 'LaTeX' type.
--
module Text.LaTeX.Base.Writer
 ( -- * @LaTeXT@ writer
   LaTeXT
 , runLaTeXT
 , execLaTeXT
   -- ** Synonyms
 , LaTeXT_
 , LaTeXM
 , runLaTeXM
 , execLaTeXM
   -- * Utils
 , execLaTeXTWarn
 , extractLaTeX
 , extractLaTeX_
 , textell
 , rendertexM
 , liftFun
 , liftOp
 , mapLaTeXT
   -- * Re-exports
 , lift
 , liftIO
   ) where

-- base
import Control.Arrow
import Data.String
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
import Control.Applicative
import qualified Data.Semigroup as Semigroup
-- transformers
import Control.Monad.Trans.Writer
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Functor.Identity
-- HaTeX
import Text.LaTeX.Base.Syntax
import Text.LaTeX.Base.Class
import Text.LaTeX.Base.Render
import Text.LaTeX.Base.Warnings (Warning,checkAll,check)

-- | 'WriterT' monad transformer applied to 'LaTeX' values.
newtype LaTeXT m a = LaTeXT { forall (m :: * -> *) a. LaTeXT m a -> WriterT LaTeX m a
unwrapLaTeXT :: WriterT LaTeX m a }

instance Functor f => Functor (LaTeXT f) where
    fmap :: forall a b. (a -> b) -> LaTeXT f a -> LaTeXT f b
fmap a -> b
f = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> WriterT LaTeX m a
unwrapLaTeXT

instance Applicative f => Applicative (LaTeXT f) where
    pure :: forall a. a -> LaTeXT f a
pure = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (LaTeXT WriterT LaTeX f (a -> b)
f) <*> :: forall a b. LaTeXT f (a -> b) -> LaTeXT f a -> LaTeXT f b
<*> (LaTeXT WriterT LaTeX f a
x) = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall a b. (a -> b) -> a -> b
$ WriterT LaTeX f (a -> b)
f forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> WriterT LaTeX f a
x

-- | Type synonym for empty 'LaTeXT' computations.
type LaTeXT_ m = LaTeXT m ()

-- | The 'LaTeXT' monad transformed applied to 'Identity'.
type LaTeXM = LaTeXT Identity

-- | A particular case of 'runLaTeXT'.
--
-- > runLaTeXM = runIdentity . runLaTeXT
--
runLaTeXM :: LaTeXM a -> (a, LaTeX)
runLaTeXM :: forall a. LaTeXM a -> (a, LaTeX)
runLaTeXM = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> m (a, LaTeX)
runLaTeXT

-- | A particular case of 'execLaTeXT'.
--
-- > execLaTeXM = runIdentity . execLaTeXT
--
execLaTeXM :: LaTeXM a -> LaTeX
execLaTeXM :: forall a. LaTeXM a -> LaTeX
execLaTeXM = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => LaTeXT m a -> m LaTeX
execLaTeXT

instance MonadTrans LaTeXT where
 lift :: forall (m :: * -> *) a. Monad m => m a -> LaTeXT m a
lift = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

instance Monad m => Monad (LaTeXT m) where
 (LaTeXT WriterT LaTeX m a
c) >>= :: forall a b. LaTeXT m a -> (a -> LaTeXT m b) -> LaTeXT m b
>>= a -> LaTeXT m b
f = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall a b. (a -> b) -> a -> b
$ do 
  a
a <- WriterT LaTeX m a
c
  let LaTeXT WriterT LaTeX m b
c' = a -> LaTeXT m b
f a
a
  WriterT LaTeX m b
c'

instance MonadIO m => MonadIO (LaTeXT m) where
 liftIO :: forall a. IO a -> LaTeXT m a
liftIO = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO

instance (Monad m, a ~ ()) => LaTeXC (LaTeXT m a) where
 liftListL :: ([LaTeX] -> LaTeX) -> [LaTeXT m a] -> LaTeXT m a
liftListL [LaTeX] -> LaTeX
f [LaTeXT m a]
xs = forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall (m :: * -> *) a. Monad m => LaTeXT m a -> LaTeXT m LaTeX
extractLaTeX_ [LaTeXT m a]
xs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *). Monad m => LaTeX -> LaTeXT m ()
textell forall b c a. (b -> c) -> (a -> b) -> a -> c
. [LaTeX] -> LaTeX
f

-- | Running a 'LaTeXT' computation returns the final 'LaTeX' value.
runLaTeXT :: LaTeXT m a -> m (a,LaTeX)
runLaTeXT :: forall (m :: * -> *) a. LaTeXT m a -> m (a, LaTeX)
runLaTeXT = forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> WriterT LaTeX m a
unwrapLaTeXT

-- | This is the usual way to run the 'LaTeXT' monad
--   and obtain a 'LaTeX' value.
--
-- > execLaTeXT = liftM snd . runLaTeXT
--
-- If @anExample@ is defined as above (at the top of this module
-- documentation), use the following to get the LaTeX value
-- generated out.
--
-- > myLaTeX :: Monad m => m LaTeX
-- > myLaTeX = execLaTeXT anExample
--
execLaTeXT :: Monad m => LaTeXT m a -> m LaTeX
execLaTeXT :: forall (m :: * -> *) a. Monad m => LaTeXT m a -> m LaTeX
execLaTeXT = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> m (a, LaTeX)
runLaTeXT

-- | Version of 'execLaTeXT' with possible warning messages.
--   This function applies 'checkAll' to the 'LaTeX' output.
execLaTeXTWarn :: Monad m => LaTeXT m a -> m (LaTeX,[Warning])
execLaTeXTWarn :: forall (m :: * -> *) a.
Monad m =>
LaTeXT m a -> m (LaTeX, [Warning])
execLaTeXTWarn = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. a -> a
id forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& TeXCheck -> LaTeX -> [Warning]
check TeXCheck
checkAll) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => LaTeXT m a -> m LaTeX
execLaTeXT

-- | This function run a 'LaTeXT' computation,
--   lifting the result again in the monad.
extractLaTeX :: Monad m => LaTeXT m a -> LaTeXT m (a,LaTeX)
extractLaTeX :: forall (m :: * -> *) a.
Monad m =>
LaTeXT m a -> LaTeXT m (a, LaTeX)
extractLaTeX = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> WriterT LaTeX m a
unwrapLaTeXT

-- | Executes a 'LaTeXT' computation, embedding it again in
--   the 'LaTeXT' monad.
--
-- > extractLaTeX_ = liftM snd . extractLaTeX
--
-- This function was heavily used in the past by HaTeX-meta
-- to generate those @.Monad@ modules. The current purpose
-- is to implement the 'LaTeXC' instance of 'LaTeXT', which
-- is closely related.
extractLaTeX_ :: Monad m => LaTeXT m a -> LaTeXT m LaTeX
extractLaTeX_ :: forall (m :: * -> *) a. Monad m => LaTeXT m a -> LaTeXT m LaTeX
extractLaTeX_ = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
Monad m =>
LaTeXT m a -> LaTeXT m (a, LaTeX)
extractLaTeX

-- | With 'textell' you can append 'LaTeX' values to the
--   state of the 'LaTeXT' monad.
textell :: Monad m => LaTeX -> LaTeXT m ()
textell :: forall (m :: * -> *). Monad m => LaTeX -> LaTeXT m ()
textell = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
tell

-- | Lift a function over 'LaTeX' values to a function
--   acting over the state of a 'LaTeXT' computation.
liftFun :: Monad m
        => (LaTeX -> LaTeX)
        -> (LaTeXT m a -> LaTeXT m a)
liftFun :: forall (m :: * -> *) a.
Monad m =>
(LaTeX -> LaTeX) -> LaTeXT m a -> LaTeXT m a
liftFun LaTeX -> LaTeX
f (LaTeXT WriterT LaTeX m a
c) = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall a b. (a -> b) -> a -> b
$ do
 (a
p,LaTeX
l) <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT WriterT LaTeX m a
c
 forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
tell forall a b. (a -> b) -> a -> b
$ LaTeX -> LaTeX
f LaTeX
l
 forall (m :: * -> *) a. Monad m => a -> m a
return a
p

-- | Lift an operator over 'LaTeX' values to an operator
--   acting over the state of two 'LaTeXT' computations.
--
-- /Note: The returned value is the one returned by the/
-- /second argument of the lifted operator./
liftOp :: Monad m
       => (LaTeX -> LaTeX -> LaTeX)
       -> (LaTeXT m a -> LaTeXT m b -> LaTeXT m b)
liftOp :: forall (m :: * -> *) a b.
Monad m =>
(LaTeX -> LaTeX -> LaTeX) -> LaTeXT m a -> LaTeXT m b -> LaTeXT m b
liftOp LaTeX -> LaTeX -> LaTeX
op (LaTeXT WriterT LaTeX m a
c) (LaTeXT WriterT LaTeX m b
c') = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall a b. (a -> b) -> a -> b
$ do
 (a
_,LaTeX
l)  <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT WriterT LaTeX m a
c
 (b
p,LaTeX
l') <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT WriterT LaTeX m b
c'
 forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
tell forall a b. (a -> b) -> a -> b
$ LaTeX
l LaTeX -> LaTeX -> LaTeX
`op` LaTeX
l'
 forall (m :: * -> *) a. Monad m => a -> m a
return b
p

-- | A helper function for building monad transformers, e.g.
--
-- > instance MonadReader r m => MonadReader r (LaTeXT m) where
-- >   ask = lift ask
-- >   local = mapLaTeXT . local
--
-- This declaration could be included here, but it would add a
-- dependency on mtl.
mapLaTeXT :: (m (a, LaTeX) -> m (a, LaTeX)) -> LaTeXT m a -> LaTeXT m a
mapLaTeXT :: forall (m :: * -> *) a.
(m (a, LaTeX) -> m (a, LaTeX)) -> LaTeXT m a -> LaTeXT m a
mapLaTeXT m (a, LaTeX) -> m (a, LaTeX)
f = forall (m :: * -> *) a. WriterT LaTeX m a -> LaTeXT m a
LaTeXT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a w (n :: * -> *) b w'.
(m (a, w) -> n (b, w')) -> WriterT w m a -> WriterT w' n b
mapWriterT m (a, LaTeX) -> m (a, LaTeX)
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. LaTeXT m a -> WriterT LaTeX m a
unwrapLaTeXT

-- | Just like 'rendertex', but with 'LaTeXT' output.
--
-- > rendertexM = textell . rendertex
--
rendertexM :: (Render a, Monad m) => a -> LaTeXT m ()
rendertexM :: forall a (m :: * -> *). (Render a, Monad m) => a -> LaTeXT m ()
rendertexM = forall (m :: * -> *). Monad m => LaTeX -> LaTeXT m ()
textell forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a l. (Render a, LaTeXC l) => a -> l
rendertex

-- Overloaded Strings

instance (Monad m, a ~ ()) => IsString (LaTeXT m a) where
 fromString :: String -> LaTeXT m a
fromString = forall (m :: * -> *). Monad m => LaTeX -> LaTeXT m ()
textell forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IsString a => String -> a
fromString

-- Monoids

instance (Monad m, Monoid a) => Monoid (LaTeXT m a) where
 mempty :: LaTeXT m a
mempty = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Monoid a => a
mempty

instance (Applicative m, Semigroup.Semigroup a) => Semigroup.Semigroup (LaTeXT m a) where
  <> :: LaTeXT m a -> LaTeXT m a -> LaTeXT m a
(<>) = forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 forall a. Semigroup a => a -> a -> a
(Semigroup.<>)