packages feed

hatex-guide-1.3.1.2: src/monad.htxg

#LaTeX blocks and the Writer monad#

##The Writer Monad##
For any given 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\} (the 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 about the element of \{m\}: there is only one element that it could be!
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 similarly to each other. 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 a standard definition, valid for any monad.

What we have done here is to hide a monoid in a monad, with all its operations. We have created a
machine that operates on monoidal 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 the result of operating on all the values we have put into 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 corresponding \{Writer\} monad.

\[
type LaTeXW = W LaTeX
\]

The \{W\} machine is now waiting 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 these blocks into the machine, and it returns the concatenated block for us. We just saved a lot of
\{mappend\}'s, but we now have a lot of \{tell\}'s instead. No problem, just redefine each function of
blocks using \{tell\} and \{execute\}.

\[
author' :: LaTeXW a -> LaTeXW ()
author' = tell . author . execute
\]

If this is done in a similar way to \{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 duplicated all of our functions.
This is why the \{LaTeXC\} class exists. We'll talk about this later.

##Composing monads##

To add flexibility to \hatex, the writer monad explained above is defined as a monad transformer,
named \{LaTeXT\}. The way we use it is the same, with just a few small changes.

The first change is in the type signature. We need to carry an inner monad in every type.

\[
foo :: Monad m => LaTeXT m a
\]

However, in practice, we can avoid this by using type aliases. Say we're going to use a specific monad \{M\}.

\[
type LaTeXW = LaTeXT M

foo :: LaTeXW a
\]

Now, the type signatures go back to the way they were.

The other change is a new feature: the \{lift\} function. With it we can do any computation
on our inner monad at any time. For example, suppose we want to output some code we have in
the file /foo.hs/. Instead of copying all of its content, or reading and carrying it as an argument along in 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 each give different features. In the case where we're not interested in any of
these features, we can simply use the Identity monad.

\[
type LaTeXW = LaTeXT Identity
\]