diff --git a/Examples/beamer.hs b/Examples/beamer.hs
--- a/Examples/beamer.hs
+++ b/Examples/beamer.hs
@@ -35,4 +35,4 @@
   block "The block" $ do
    pause
    "The content of the block appears after a pause."
-  uncover [FromSlide 6] $ center "And that's it!"
+  uncover [FromSlide 6] $ center "And that's it!"
diff --git a/HaTeX.cabal b/HaTeX.cabal
--- a/HaTeX.cabal
+++ b/HaTeX.cabal
@@ -1,5 +1,5 @@
 Name: HaTeX
-Version: 3.10.0.0
+Version: 3.11.0.0
 Author: Daniel Díaz
 Category: Text, LaTeX
 Build-type: Simple
@@ -45,11 +45,14 @@
   Default-language: Haskell2010
   Build-depends: base == 4.*
                , bytestring >= 0.9.2.1 && < 0.11
-               , transformers >= 0.2.2 && < 0.4
+               , transformers >= 0.2.2 && < 0.5
                , text >= 0.11.2.3 && < 2
                , attoparsec >= 0.10.2 && < 0.12
                , matrix
                , containers >= 0.4.2.1 && < 0.6
+               , QuickCheck
+                 -- For pretty-printing
+               , wl-pprint-extras >= 3.5
   Exposed-modules:
     Text.LaTeX
       -- Base (Core of the library)
@@ -57,6 +60,7 @@
         Text.LaTeX.Base.Class
         Text.LaTeX.Base.Commands
         Text.LaTeX.Base.Parser
+        Text.LaTeX.Base.Pretty
         Text.LaTeX.Base.Render
         Text.LaTeX.Base.Syntax
         Text.LaTeX.Base.Texy
@@ -88,3 +92,13 @@
   Default-extensions: OverloadedStrings
   Other-extensions: CPP
   ghc-options: -Wall -fno-warn-orphans
+
+Test-Suite matrix-test
+  type: exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is: Main.hs
+  build-depends: base == 4.*
+               , HaTeX
+               , tasty
+               , QuickCheck
+               , tasty-quickcheck
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -25,6 +25,8 @@
 In the other hand, this package follows the [_Package Versioning Policy_](http://www.haskell.org/haskellwiki/Package_versioning_policy),
 so it is unlikely to suffer from API breakages if you follow it too when importing the library.
 
+See the [Hackage page of HaTeX](http://hackage.haskell.org/package/HaTeX) to browse older versions.
+
 ## Travis automatic build
 
 [![Build Status](https://travis-ci.org/Daniel-Diaz/HaTeX.png?branch=master)](https://travis-ci.org/Daniel-Diaz/HaTeX)
@@ -57,10 +59,6 @@
   This includes adding more test cases to the [parsertest folder](https://github.com/Daniel-Diaz/HaTeX/tree/master/parsertest).
 * Add more documentation.
 * BibTeX support.
-
-## Packages to be implemented
-
-* geometry
 
 ## Related projects
 
diff --git a/Text/LaTeX/Base/Commands.hs b/Text/LaTeX/Base/Commands.hs
--- a/Text/LaTeX/Base/Commands.hs
+++ b/Text/LaTeX/Base/Commands.hs
@@ -848,7 +848,7 @@
 
 -- | Column separator.
 (&) :: LaTeXC l => l -> l -> l
-(&) = liftL2 $ TeXOp "&"
+(&) = between "&"
 
 -- | Horizontal line.
 hline :: LaTeXC l => l
diff --git a/Text/LaTeX/Base/Pretty.hs b/Text/LaTeX/Base/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/Text/LaTeX/Base/Pretty.hs
@@ -0,0 +1,77 @@
+
+-- | 'LaTeX' values pretty printer.
+--
+--   Still experimental. Give it a try and send us your feedback! :)
+module Text.LaTeX.Base.Pretty (
+    -- * @LaTeX@ pretty printer
+    prettyLaTeX
+    -- * Configurable printer
+  , docLaTeX
+  ) where
+
+import Text.LaTeX.Base.Syntax
+import Text.LaTeX.Base.Render
+import Text.PrettyPrint.Free
+  ( Doc, text, char
+  , backslash, hardline
+  , braces, brackets
+  , indent, align, vsep
+  , list, encloseSep
+  , renderSmart, displayS
+    )
+import Data.Text (unpack,lines)
+import Data.Monoid (mconcat,mempty)
+
+-- | This function transforms a value of type 'LaTeX' to a 'Doc'.
+--   You can then choose how to print this 'Doc' value using
+--   the function from the "Text.PrettyPrint.Free" module.
+docLaTeX :: LaTeX -> Doc ()
+docLaTeX (TeXRaw t) = text $ unpack t
+docLaTeX (TeXComm n as) = backslash <> text n <> align (mconcat (fmap docTeXArg as)) <> hardline
+docLaTeX (TeXCommS n) = backslash <> text n <> hardline
+docLaTeX (TeXEnv n as b) =
+  let a = FixArg $ fromString n
+  in  mconcat
+       [ hardline
+       , docLaTeX $ TeXComm "begin" $ a : as
+       , indent 4 $ docLaTeX b
+       , hardline
+       , docLaTeX $ TeXComm "end" [a]
+         ]
+docLaTeX (TeXMath t b) =
+  let (l,r) =
+        case t of
+          Parentheses -> ("\\(","\\)")
+          Square -> ("\\[","\\]")
+          Dollar -> ("$","$")
+  in  text l <> docLaTeX b <> text r
+docLaTeX (TeXLineBreak m b) =
+  text "\\\\" <> maybe mempty (brackets . text . unpack . render) m <> ( if b then text "*" else mempty )
+docLaTeX (TeXBraces b) = braces $ docLaTeX b
+docLaTeX (TeXComment t) =
+  let ls = Data.Text.lines t
+  in  if null ls
+         then char '%' <> hardline
+         else align $ vsep $ fmap (text . ("% "++) . unpack) ls
+docLaTeX (TeXSeq l1 l2) = docLaTeX l1 <> docLaTeX l2
+docLaTeX TeXEmpty = mempty
+
+docTeXArg :: TeXArg -> Doc ()
+docTeXArg (FixArg l) = braces $ docLaTeX l
+docTeXArg (OptArg l) = brackets $ docLaTeX l
+docTeXArg (MOptArg ls) =
+  if null ls then mempty
+             else list $ fmap docLaTeX ls
+docTeXArg (SymArg l) = docTeXArg $ MSymArg [l]
+docTeXArg (MSymArg ls) = encloseSep (char '<') (char '>') (char ',') $ fmap docLaTeX ls
+
+-- | Pretty print a 'LaTeX' value. It produces a more human-friendly output than 'render'.
+--
+--   This function should be used only for debugging purposes since it may change
+--   the semantics of the input in order to create a prettier output.
+--   In other words, running a LaTeX compiler in the output file of @renderFile fp l@ may
+--   produce a different document than running it in the output of @writeFile fp (prettyLaTeX l)@.
+--   You should use 'renderFile' unless you really need to read the LaTeX file.
+--
+prettyLaTeX :: LaTeX -> String
+prettyLaTeX l = displayS (renderSmart 60 (docLaTeX l)) []
diff --git a/Text/LaTeX/Base/Render.hs b/Text/LaTeX/Base/Render.hs
--- a/Text/LaTeX/Base/Render.hs
+++ b/Text/LaTeX/Base/Render.hs
@@ -129,8 +129,6 @@
 
   render (TeXLineBreak m b) = "\\\\" <> maybe mempty (\x -> "[" <> render x <> "]") m <> ( if b then "*" else mempty )
 
-  render (TeXOp sym l1 l2) = render l1 <> fromString sym <> render l2
-
   render (TeXBraces l) = "{" <> render l <> "}"
 
   render (TeXComment c) =
diff --git a/Text/LaTeX/Base/Syntax.hs b/Text/LaTeX/Base/Syntax.hs
--- a/Text/LaTeX/Base/Syntax.hs
+++ b/Text/LaTeX/Base/Syntax.hs
@@ -26,13 +26,15 @@
  , getPreamble
    ) where
 
-import Data.Text (Text)
+import Data.Text (Text,pack)
 import qualified Data.Text
 import Data.Monoid
 import Data.String
 import Control.Applicative
+import Control.Monad (replicateM)
 import Data.Functor.Identity (runIdentity)
 import Data.Typeable
+import Test.QuickCheck
 
 -- | Measure units defined in LaTeX. Use 'CustomMeasure' to use commands like 'textwidth'.
 --   For instance:
@@ -62,13 +64,14 @@
                            -- First argument is the name of the command.
                            -- Second, its arguments.
  | TeXCommS String -- ^ Constructor for commands with no arguments.
+                   --   When rendering, no space or @{}@ will be added at
+                   --   the end.
  | TeXEnv String [TeXArg] LaTeX -- ^ Constructor for environments.
                                 -- First argument is the name of the environment.
                                 -- Second, its arguments.
                                 -- Third, its content.
  | TeXMath MathType LaTeX -- ^ Mathematical expressions.
  | TeXLineBreak (Maybe Measure) Bool -- ^ Line break command.
- | TeXOp String LaTeX LaTeX -- ^ Operators.
  | TeXBraces LaTeX -- ^ A expression between braces.
  | TeXComment Text -- ^ Comments.
  | TeXSeq LaTeX LaTeX -- ^ Sequencing of 'LaTeX' expressions.
@@ -161,7 +164,6 @@
   let xs = concatMap (matchCommandArg f) as
   in  xs ++ matchCommand f l
 matchCommand f (TeXMath _ l) = matchCommand f l
-matchCommand f (TeXOp _ l1 l2) = matchCommand f l1 ++ matchCommand f l2
 matchCommand f (TeXBraces l) = matchCommand f l
 matchCommand f (TeXSeq l1 l2) = matchCommand f l1 ++ matchCommand f l2
 matchCommand _ _ = []
@@ -193,7 +195,6 @@
       zs = xs ++ ys
   in  if f str then (str,as,l) : zs else zs
 matchEnv f (TeXMath _ l) = matchEnv f l
-matchEnv f (TeXOp _ l1 l2) = matchEnv f l1 ++ matchEnv f l2
 matchEnv f (TeXBraces l) = matchEnv f l
 matchEnv f (TeXSeq l1 l2) = matchEnv f l1 ++ matchEnv f l2
 matchEnv _ _ = []
@@ -224,7 +225,6 @@
    go l@(TeXComm str as)  = if c l then f l else TeXComm str <$> mapM go' as
    go l@(TeXEnv str as b) = if c l then f l else TeXEnv str <$> mapM go' as <*> go b
    go l@(TeXMath t b)     = if c l then f l else TeXMath t <$> go b
-   go l@(TeXOp str l1 l2) = if c l then f l else liftA2 (TeXOp str) (go l1) (go l2)
    go l@(TeXBraces b)     = if c l then f l else TeXBraces <$> go b
    go l@(TeXSeq l1 l2)    = if c l then f l else liftA2 TeXSeq (go l1) (go l2)
    go l = if c l then f l else pure l
@@ -248,3 +248,67 @@
 getPreamble (TeXEnv "document" _ _) = mempty
 getPreamble (TeXSeq l1 l2) = getPreamble l1 <> getPreamble l2
 getPreamble l = l
+
+---------------------------------------
+-- LaTeX Arbitrary instance
+
+arbitraryChar :: Gen Char
+arbitraryChar = elements $
+     ['A'..'Z']
+  ++ ['a'..'z']
+  ++ "\n-+*/!\"$%&()[]{}^_.,:;'#@<>?\\ "
+
+-- | Utility for the instance of 'LaTeX' to 'Arbitrary'.
+--   We generate a short sequence of characters and
+--   escape reserved characters with 'protectText'.
+arbitraryRaw :: Gen Text
+arbitraryRaw = do
+  n <- choose (1,20)
+  protectText . pack <$> replicateM n arbitraryChar
+
+-- | Generator for names of command and environments.
+--   We use only alphabetical characters.
+arbitraryName :: Gen String
+arbitraryName = do
+  n <- choose (1,10)
+  replicateM n $ elements $ ['a' .. 'z'] ++ ['A' .. 'Z']
+
+instance Arbitrary Measure where
+  arbitrary = do
+     n <- choose (0,5)
+     let f = [Pt,Mm,Cm,In,Ex,Em] !! n
+     f <$> arbitrary
+
+instance Arbitrary LaTeX where
+  arbitrary = do
+     -- We give more chances to 'TeXRaw'.
+     -- This results in arbitrary 'LaTeX' values
+     -- not getting too large.
+     n <- choose (0,16 :: Int)
+     case n of
+       0 -> pure TeXEmpty
+       1 -> do m <- choose (0,5)
+               TeXComm <$> arbitraryName <*> vectorOf m arbitrary
+       2 -> TeXCommS <$> arbitraryName
+       3 -> do m <- choose (0,5)
+               TeXEnv <$> arbitraryName <*> vectorOf m arbitrary <*> arbitrary
+       4 -> do m <- choose (0,2)
+               let t = [Parentheses,Square,Dollar] !! m
+               TeXMath <$> pure t <*> arbitrary
+       5 -> TeXLineBreak <$> arbitrary <*> arbitrary
+       6 -> TeXBraces <$> arbitrary
+       7 -> TeXComment <$> arbitraryRaw
+       8 -> TeXSeq <$> arbitrary <*> arbitrary
+       _ -> TeXRaw <$> arbitraryRaw
+
+instance Arbitrary TeXArg where
+  arbitrary = do
+     n <- choose (0,4 :: Int)
+     case n of
+       0 -> OptArg <$> arbitrary
+       1 -> do m <- choose (1,5)
+               MOptArg <$> vectorOf m arbitrary
+       2 -> SymArg <$> arbitrary
+       3 -> do m <- choose (1,5)
+               MSymArg <$> vectorOf m arbitrary
+       _ -> FixArg <$> arbitrary
diff --git a/Text/LaTeX/Base/Warnings.hs b/Text/LaTeX/Base/Warnings.hs
--- a/Text/LaTeX/Base/Warnings.hs
+++ b/Text/LaTeX/Base/Warnings.hs
@@ -110,7 +110,6 @@
   _ -> return ()
 labcheck (TeXEnv _ _ l) = labcheck l
 labcheck (TeXMath _ l) = labcheck l
-labcheck (TeXOp _ l1 l2) = labcheck l1 >> labcheck l2
 labcheck (TeXBraces l) = labcheck l
 labcheck (TeXSeq l1 l2) = labcheck l1 >> labcheck l2
 labcheck _ = return ()
diff --git a/Text/LaTeX/Base/Writer.hs b/Text/LaTeX/Base/Writer.hs
--- a/Text/LaTeX/Base/Writer.hs
+++ b/Text/LaTeX/Base/Writer.hs
@@ -34,9 +34,14 @@
 module Text.LaTeX.Base.Writer
  ( -- * @LaTeXT@ writer
    LaTeXT
- , LaTeXT_
  , runLaTeXT
  , execLaTeXT
+   -- ** Synonyms
+ , LaTeXT_
+ , LaTeXM
+ , runLaTeXM
+ , execLaTeXM
+   -- * Utils
  , execLaTeXTWarn
  , extractLaTeX
  , extractLaTeX_
@@ -47,25 +52,27 @@
    -- * Errors
  , throwError
  , merror
-   -- * Re-export
+   -- * Re-exports
  , lift
  , liftIO
    ) where
 
-import Control.Monad.Trans.Writer
-import Control.Monad.IO.Class
-import Control.Monad.Trans.Class
+-- base
 import Control.Applicative
+import Control.Monad (liftM)
 import Control.Arrow
 import Data.String
 import Data.Monoid
---
+-- 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)
---
-import Control.Monad (liftM)
 
 -- | 'WriterT' monad transformer applied to 'LaTeX' values.
 newtype LaTeXT m a =
@@ -84,6 +91,23 @@
 
 -- | 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 -> (Either String a, LaTeX)
+runLaTeXM = runIdentity . runLaTeXT
+
+-- | A particular case of 'execLaTeXT'.
+--
+-- > execLaTeXM = runIdentity . execLaTeXT
+--
+execLaTeXM :: LaTeXM a -> LaTeX
+execLaTeXM = runIdentity . execLaTeXT
 
 instance MonadTrans LaTeXT where
  lift = LaTeXT . liftM pairNoth . lift
diff --git a/Text/LaTeX/Packages/AMSMath.hs b/Text/LaTeX/Packages/AMSMath.hs
--- a/Text/LaTeX/Packages/AMSMath.hs
+++ b/Text/LaTeX/Packages/AMSMath.hs
@@ -137,8 +137,8 @@
 -- | Careful! Method 'signum' is undefined. Don't use it!
 --   This instance is defined in the "Text.LaTeX.Packages.AMSMath" module.
 instance Num LaTeX where
- (+) = TeXOp "+"
- (-) = TeXOp "-"
+ (+) = between "+"
+ (-) = between "-"
  (*) = (<>)
  negate = (TeXEmpty -)
  fromInteger = rendertex
@@ -491,7 +491,7 @@
 --
 -- > infixr 4 =:
 (=:) :: LaTeXC l => l -> l -> l
-(=:)  = liftL2 $ TeXOp "="
+(=:)  = between "="
 
 -- | Not equal (≠).
 --
@@ -501,7 +501,7 @@
 
 -- | Greater.
 (>:) :: LaTeXC l => l -> l -> l
-(>:) = liftL2 $ TeXOp ">"
+(>:) = between ">"
 
 -- | Greater or equal (≥).
 (>=:) :: LaTeXC l => l -> l -> l
@@ -509,7 +509,7 @@
 
 -- | Lesser.
 (<:) :: LaTeXC l => l -> l -> l
-(<:) = liftL2 $ TeXOp "<"
+(<:) = between "<"
 
 -- | Lesser or equal (≤).
 (<=:) :: LaTeXC l => l -> l -> l
diff --git a/Text/LaTeX/Packages/Hyperref.hs b/Text/LaTeX/Packages/Hyperref.hs
--- a/Text/LaTeX/Packages/Hyperref.hs
+++ b/Text/LaTeX/Packages/Hyperref.hs
@@ -45,6 +45,8 @@
 
 createURL :: String -> URL
 createURL = URL
+-- TODO: This function should check that the input
+-- String is a valid URL.
 
 -- | 'fromString' = 'createURL'.
 instance IsString URL where
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,25 @@
+
+import Text.LaTeX
+import Text.LaTeX.Base.Parser
+
+import Test.Tasty
+import qualified Test.Tasty.QuickCheck as QC
+import Test.QuickCheck
+
+main :: IO ()
+main = defaultMain $ testGroup "HaTeX"
+  [ testGroup "LaTeX"
+    [ QC.testProperty "LaTeX mempty" $
+         \l -> (mempty <> l) == (l <> mempty)
+            && (mempty <> l) == (l :: LaTeX)
+    , QC.testProperty "LaTeX mappend" $
+         \l1 l2 l3 -> render (l1 <> (l2 <> l3)) == render ((l1 <> l2) <> (l3 :: LaTeX))
+    ]
+  , testGroup "Parser"
+    [ QC.testProperty "render . parse = id" $
+         \l0 -> let t = render (l0 :: LaTeX)
+                in case parseLaTeX t of
+                     Left _ -> False
+                     Right l -> render l == t
+    ]
+  ]
