hatex-guide-1.2.0.0: src/monad.htxg
#LaTeX blocks and the Writer monad#
##The Writer Monad##
Fixed a monoid \{M\}, the \{M\}-writer monad is just all possible pairs of elements from \{M\}
and elements from other types. Thus, the Haskell declaration is as follows\f
Some authors write it using tuples, like this: \{data W m a = W (a,m)\}.\f:
\[
data W m a = W m a
\]
Note that to get the monad we need to fix the type \{m\} (kind of monads is \{* -> *\}). To inject
an arbitrary value into the monad (the Haskell \{return\} function) we use the neutral element (\{mempty\})
of the monoid.
\[
inject :: Monoid m => a -> W m a
inject a = W mempty a
\]
Think that no other element of \{m\} is possible to think: it is the only element we know of it!
Like any other monad, \{W m\} is also a \{Functor\}. We just apply the function to the value.
\[
instance Functor (W m) where
fmap f (W m a) = W m (f a)
\]
Every \{Monad\} instance can be given by the two monad operations \{inject\} and \{join\}. We already
defined the \{inject\} function. The other one deletes one monad type constructor.
\[
join :: Monoid m => W m (W m a) -> W m a
join (W m (W m' a)) = W (mappend m m') a
\]
In this function we use the other \{Monoid\} method to combine both values. It is important to
note that in both monad operations \{inject\} and \{join\} we used \{mempty\} and \{mappend\}
respectively. In practice, this is because they act equal. Indeed, they are equal if we forget the
\{a\} value. Now, we are ready to define the \{Monad\} instance:
\[
instance Monoid m => Monad (W m) where
return = inject
w >>= f = join (fmap f w)
\]
There is nothing to say about this instance. It is and standard definition valid to any monad.
What we have done here is to hide in a monad a monoid with all its operations. We have created a
machine that operates monoid values. To insert a value into the machine we need the \{tell\}
function:
\[
tell :: m -> W m ()
tell m = W m ()
\]
When we execute the machine, it returns to us the result of operate all the values we have put on it.
\[
execute :: W m a -> m
execute (W m a) = m
\]
Let's see the machine working. For example, the \{Int\} type with addition forms a \{Monoid\}.
\[
instance Monoid Int where
mempty = 0
mappend = (+)
example :: Int
example = execute $ do
tell 1
tell 2
tell 3
tell 4
\]
When we evaluate \{example\} we get \{10\}, as expected. Using \{mapM_\} we can rewrite \{example\}.
\[
example :: Int
example = execute $ mapM_ tell [ 1 .. 4 ]
\]
|machine.png|
##The LaTeX Monad##
Let's go back to the \{LaTeX\} type. Since \{LaTeX\} is an instance of \{Monoid\} we can construct
its correspondent \{Writer\} monad.
\[
type LaTeXW = W LaTeX
\]
The \{W\} machine is waiting now for \{LaTeX\} values.
\[
example :: LaTeX
example = execute $ do
tell $ documentclass [] article
tell $ author "Monads lover"
tell $ title "LaTeX and the Writer Monad"
\]
We put all that blocks in the machine, and it returns the concatenated block. We saved a lot of
\{mappend\}'s, but we now have a lot of \{tell\}'s. No problem. Just redefine each function of
blocks with \{tell\} and \{execute\}.
\[
author' :: LaTeXW a -> LaTeXW ()
author' = tell . author . execute
\]
If it is done in a similar way with \{documentclass\} and \{title\}, every \{tell\} in \{example\}
disappears.
\[
example :: LaTeX
example = execute $ do
documentclass' [] article
author' "Monads lover"
title' "LaTeX and the Writer Monad"
\]
And we can now use the \{LaTeX\} machine more comfortably. However, we have all functions duplicated.
This is why the \{LaTeXC\} class exists. We are going to talk about it later.
##Composing monads##
To add flexibility to \hatex, the writer monad explained above is defined as a monad transformer,
named \{LaTeXT\}. The way to use it is the same, there are just a few changes.
The first change is in type signatures. We need to carry an inner monad in every type.
\[
foo :: Monad m => LaTeXT m a
\]
However, in practice, we can avoid it. Say we going to use an specific monad \{M\}.
\[
type LaTeXW = LaTeXT M
foo :: LaTeXW a
\]
Now, type signatures remain unchanged.
The other change is a new feature: the \{lift\} function. With it we can do any computation
of our inner monad at any time. For example, suppose we want to output some code we have in
the file /foo.hs/. Instead of copy all its content, or read and carry it as an argument along the code,
you can simply read that file using \{lift\} wherever you want.
\[
type LaTeXIO = LaTeXT IO
readCode :: FilePath -> LaTeXIO ()
readCode fp = lift (readFileTex fp) >>= verbatim . raw
example :: LaTeXIO ()
example = do
"This is the code I wrote this morning:"
readCode "foo.hs"
"It was a funny exercise."
\]
Different monads will give different features. In the case we are not interested in any of
these features, it is enough to use the Identity monad.
\[
type LaTeXW = LaTeXT Identity
\]