diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,3 @@
 import Distribution.Simple
+
 main = defaultMain
diff --git a/lambdatex.cabal b/lambdatex.cabal
--- a/lambdatex.cabal
+++ b/lambdatex.cabal
@@ -1,68 +1,69 @@
-name:                lambdatex
-version:             0.1.1.0
-synopsis:            Type-Safe LaTeX EDSL
-description:         
-  ΛTeX, pronounced 'LambdaTeX' is a Haskell EDSL that adds type-safety to LaTeX.
-  ΛTeX-generated LaTeX code should compile without errors.
+name: lambdatex
+version: 0.2.0.0
+cabal-version: >=1.10
+build-type: Simple
+license: GPL
+license-file: LICENSE
+copyright: 2015 Tom Sydney Kerckhove
+maintainer: syd.kerckhove@gmail.com
+homepage: http://github.com/NorfairKing/lambdatex
+synopsis: Type-Safe LaTeX EDSL
+description:
+    ΛTeX, pronounced 'LambdaTeX' is a Haskell EDSL that adds type-safety to LaTeX.
+    ΛTeX-generated LaTeX code should compile without errors.
+    TODO(kerckhove) big fancy example
+category: Text
+author: Tom Sydney Kerckhove
 
-  TODO(kerckhove) big fancy example
-homepage:            http://github.com/NorfairKing/lambdatex
-license:             GPL
-license-file:        LICENSE
-author:              Tom Sydney Kerckhove
-maintainer:          syd.kerckhove@gmail.com
-copyright:           2015 Tom Sydney Kerckhove
-category:            Text
-build-type:          Simple
--- extra-source-files:
-cabal-version:       >=1.10
+source-repository head
+    type: git
+    location: https://github.com/NorfairKing/lambdatex
 
 library
-  hs-source-dirs:      src
-  exposed-modules:     Text.LaTeX.LambdaTeX
-                       Text.LaTeX.LambdaTeX.Action
-                       Text.LaTeX.LambdaTeX.Error
-                       Text.LaTeX.LambdaTeX.Package
-                       Text.LaTeX.LambdaTeX.Package.Internal
-                       Text.LaTeX.LambdaTeX.Package.Types
-                       Text.LaTeX.LambdaTeX.Part
-                       Text.LaTeX.LambdaTeX.Reference
-                       Text.LaTeX.LambdaTeX.Reference.Internal
-                       Text.LaTeX.LambdaTeX.Reference.Types
-                       Text.LaTeX.LambdaTeX.Selection
-                       Text.LaTeX.LambdaTeX.Selection.Internal
-                       Text.LaTeX.LambdaTeX.Selection.Types
-                       Text.LaTeX.LambdaTeX.Types
-                       Text.LaTeX.LambdaTeX.Utils
-  build-depends:       base             >= 4.8      && < 5.0
-                     , HaTeX            >= 3.16     && < 3.18
-                     , mtl              >= 2.2      && < 2.3
-                     , text             >= 1.2      && < 1.3
-                     , containers       >= 0.5      && < 0.6
-                     , transformers     >= 0.4      && < 0.6
-                     , directory        >= 1.2      && < 1.3
-                     , async            >= 2.0      && < 2.2
-  ghc-options:        -Wall
-                      -fwarn-unused-imports
-                      -fwarn-incomplete-patterns
-                      -fno-warn-unused-do-bind
-                      -fno-warn-name-shadowing
-                      -fno-warn-orphans
-  default-language:    Haskell2010
+    exposed-modules:
+        Text.LaTeX.LambdaTeX
+        Text.LaTeX.LambdaTeX.Action
+        Text.LaTeX.LambdaTeX.Error
+        Text.LaTeX.LambdaTeX.Package
+        Text.LaTeX.LambdaTeX.Package.Internal
+        Text.LaTeX.LambdaTeX.Package.Types
+        Text.LaTeX.LambdaTeX.Part
+        Text.LaTeX.LambdaTeX.Reference
+        Text.LaTeX.LambdaTeX.Reference.Internal
+        Text.LaTeX.LambdaTeX.Reference.Types
+        Text.LaTeX.LambdaTeX.Selection
+        Text.LaTeX.LambdaTeX.Selection.Internal
+        Text.LaTeX.LambdaTeX.Selection.Types
+        Text.LaTeX.LambdaTeX.Types
+        Text.LaTeX.LambdaTeX.Utils
+    build-depends:
+        base >=4.8 && <5.0,
+        HaTeX >=3.16 && <3.18,
+        mtl >=2.2 && <2.3,
+        text >=1.2 && <1.3,
+        containers >=0.5 && <0.6,
+        transformers >=0.4 && <0.6,
+        directory >=1.2 && <1.4,
+        async >=2.0 && <2.2,
+        filepath >=1.4 && <1.5
+    default-language: Haskell2010
+    hs-source-dirs: src
+    ghc-options: -Wall -fwarn-unused-imports -fwarn-incomplete-patterns -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-orphans
 
 test-suite lambdatex-test
-  type:                exitcode-stdio-1.0
-  hs-source-dirs:      test
-  main-is:             MainTest.hs
-  build-depends:       base
-                     , lambdatex
-                     , hspec
-                     , QuickCheck
-                     , text             >= 1.2      && < 1.3
-                     , quickcheck-text  >= 0.1      && < 0.2
-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
-  default-language:    Haskell2010
-
-source-repository head
-  type:     git
-  location: https://github.com/NorfairKing/lambdatex
+    type: exitcode-stdio-1.0
+    main-is: MainTest.hs
+    build-depends:
+        base -any,
+        lambdatex -any,
+        hspec -any,
+        QuickCheck -any,
+        text >=1.2 && <1.3,
+        quickcheck-text >=0.1 && <0.2
+    default-language: Haskell2010
+    hs-source-dirs: test
+    other-modules:
+        Text.LaTeX.LambdaTeX.Part.Arbitrary
+        Text.LaTeX.LambdaTeX.Selection.Arbitrary
+        Text.LaTeX.LambdaTeX.Selection.InternalSpec
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N
diff --git a/src/Text/LaTeX/LambdaTeX.hs b/src/Text/LaTeX/LambdaTeX.hs
--- a/src/Text/LaTeX/LambdaTeX.hs
+++ b/src/Text/LaTeX/LambdaTeX.hs
@@ -2,47 +2,41 @@
 -- TODO(kerckhove) big example here!
 --
 {-# LANGUAGE OverloadedStrings #-}
-module Text.LaTeX.LambdaTeX (
-    -- * Building ΛTeX
-      module Text.LaTeX.LambdaTeX
 
+module Text.LaTeX.LambdaTeX
+    ( module Text.LaTeX.LambdaTeX
     -- ** Selections
     , module Text.LaTeX.LambdaTeX.Selection
-
     -- ** References
     , module Text.LaTeX.LambdaTeX.Reference
-
     -- ** Packages dependencies
     , module Text.LaTeX.LambdaTeX.Package
-
     -- ** IO dependencies
     , module Text.LaTeX.LambdaTeX.Action
-
     -- ** Re-exports
     , module Text.LaTeX.LambdaTeX.Types
-
     ) where
 
-import           Control.Monad                           (forM_, void)
-import           Control.Monad.IO.Class                  (MonadIO (..))
+import Control.Monad (forM_, void)
+import Control.Monad.IO.Class (MonadIO(..))
 
-import           Control.Concurrent.Async                (async, wait)
+import Control.Concurrent.Async (async, wait)
+import System.FilePath
 
-import qualified Data.Set                                as S
-import qualified Data.Text.IO                            as T
+import qualified Data.Set as S
+import qualified Data.Text.IO as T
 
-import           Text.LaTeX.Base                         (LaTeX, renderFile)
+import Text.LaTeX.Base (LaTeX, renderFile)
 
-import           Text.LaTeX.LambdaTeX.Action
-import           Text.LaTeX.LambdaTeX.Package
-import           Text.LaTeX.LambdaTeX.Package.Internal
-import           Text.LaTeX.LambdaTeX.Reference
-import           Text.LaTeX.LambdaTeX.Reference.Internal
-import           Text.LaTeX.LambdaTeX.Reference.Types
-import           Text.LaTeX.LambdaTeX.Selection
-import           Text.LaTeX.LambdaTeX.Selection.Types
-import           Text.LaTeX.LambdaTeX.Types
-import           Text.LaTeX.LambdaTeX.Utils
+import Text.LaTeX.LambdaTeX.Action
+import Text.LaTeX.LambdaTeX.Package
+import Text.LaTeX.LambdaTeX.Package.Internal
+import Text.LaTeX.LambdaTeX.Reference
+import Text.LaTeX.LambdaTeX.Reference.Internal
+import Text.LaTeX.LambdaTeX.Reference.Types
+import Text.LaTeX.LambdaTeX.Selection
+import Text.LaTeX.LambdaTeX.Selection.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- | Build all the files for a LaTeX project given by a ΛTeXT generator
 --   This either returns Left with an error or Right () to signify success.
@@ -53,33 +47,31 @@
 --      * Automatic bibtex file generation
 --      * All safety provided by 'execLambdaTeXT' (in the form of textual errors)
 --      * Automatic asynchronic resolution of IO dependencies for graphviz or tikz figures
-buildLaTeXProject :: MonadIO m => ΛTeXT m a -> ProjectConfig -> m (Either [ΛError] ())
+buildLaTeXProject ::
+       MonadIO m => ΛTeXT m a -> ProjectConfig -> m (Either [ΛError] ())
 buildLaTeXProject func conf = do
-    (errs, latex, refs, actions) <- execLambdaTeXT func $ projectGenerationConfig conf
-
-
+    (errs, latex, refs, actions) <-
+        execLambdaTeXT func $ projectGenerationConfig conf
     -- Render tex file
     let renderTex = do
             let mainTexFile = projectTexFileName conf ++ ".tex"
-            renderFile mainTexFile latex
-
+            renderFile (projectBuildDir conf </> mainTexFile) latex
     -- Render bib file
     let renderMain = do
             let mainBibFile = projectBibFileName conf ++ ".bib"
-            removeIfExists mainBibFile
-            T.appendFile mainBibFile $ renderReferences refs
-
+            T.writeFile (projectBuildDir conf </> mainBibFile) $
+                renderReferences refs
     let performAction (name, action) = do
-            void action
+            void $ action $ projectBuildDir conf
             putStrLn $ "Job " ++ name ++ " done."
-
     -- Perform all the IO actions asynchronously
-    as <- liftIO $ mapM async $ renderTex : renderMain : map performAction actions
+    as <-
+        liftIO $ mapM async $ renderTex : renderMain : map performAction actions
     liftIO $ forM_ as wait
-
-    return $ if null errs
-        then Right ()
-        else Left errs
+    return $
+        if null errs
+            then Right ()
+            else Left errs
 
 -- | Execute a ΛTeXT generation
 --   This either returns a tuple of the errors and a tuple of the resulting LaTeX value and a list of external references that need to be put into a bibtex file.
@@ -91,60 +83,62 @@
 --      * Internal dependency safety. No more '??' for external references in the internal pdf.
 --      * Package dependency resolution, TODO(kerckhove) with packages in the right order
 --      * Dependency selection of figure dependencies on graphviz or tikz figures
-execLambdaTeXT :: Monad m => ΛTeXT m a -> GenerationConfig -> m ([ΛError], LaTeX, [Reference], [(String, IO ())])
+execLambdaTeXT ::
+       Monad m
+    => ΛTeXT m a
+    -> GenerationConfig
+    -> m ([ΛError], LaTeX, [Reference], [(String, FilePath -> IO ())])
 execLambdaTeXT func conf = do
-    ((_,latex), _, output) <- runΛTeX func (ΛConfig $ generationSelection conf) initState
-
-    let mresult = injectPackageDependencies (S.toList $ outputPackageDependencies output) latex
-    let (extraErrs, result) = case mresult of
-            Nothing -> ([IncompatibleDependencies], latex)
-            Just res -> ([], res)
-
+    ((_, latex), _, output) <-
+        runΛTeX func (ΛConfig $ generationSelection conf) initState
+    let mresult =
+            injectPackageDependencies
+                (S.toList $ outputPackageDependencies output)
+                latex
+    let (extraErrs, result) =
+            case mresult of
+                Nothing -> ([IncompatibleDependencies], latex)
+                Just res -> ([], res)
     let refs = S.toList $ outputExternalReferences output
     let actions = outputActions output
-
     -- Check reference errors
     let made = outputLabelsMade output
         needed = outputLabelsNeeded output
         diff = S.difference needed made
-
     let referss = map ReferenceMissing $ S.toList diff
-
     return (extraErrs ++ referss, result, refs, actions)
-
   where
     initState :: ΛState
-    initState = ΛState { stateCurrentPart = emptyPart }
-
+    initState = ΛState {stateCurrentPart = emptyPart}
 
 -- * Configuration
-
 -- | Configuration of a ΛTeX project
-data ProjectConfig = ProjectConfig {
-      projectGenerationConfig :: GenerationConfig
-    , projectBibFileName      :: String
-    , projectTexFileName      :: String
-    }
+data ProjectConfig = ProjectConfig
+    { projectGenerationConfig :: GenerationConfig
+    , projectBibFileName :: String
+    , projectTexFileName :: String
+    , projectBuildDir :: FilePath
+    } deriving (Show, Eq)
 
 -- | Default project configuration.
 --
 --  Modify this instead of building your own 'ProjectConfig'
 defaultProjectConfig :: ProjectConfig
-defaultProjectConfig = ProjectConfig {
-      projectGenerationConfig = defaultGenerationConfig
+defaultProjectConfig =
+    ProjectConfig
+    { projectGenerationConfig = defaultGenerationConfig
     , projectBibFileName = "main"
     , projectTexFileName = "main"
+    , projectBuildDir = "."
     }
 
 -- | Configuration of ΛTeX generation
-data GenerationConfig = GenerationConfig {
-      generationSelection :: Selection
-    }
+newtype GenerationConfig = GenerationConfig
+    { generationSelection :: Selection
+    } deriving (Show, Eq)
 
 -- | Default generation config.
 --
 --  Modify this instead of building your own 'GenerationConfig'
 defaultGenerationConfig :: GenerationConfig
-defaultGenerationConfig = GenerationConfig {
-      generationSelection = [All]
-    }
+defaultGenerationConfig = GenerationConfig {generationSelection = [All]}
diff --git a/src/Text/LaTeX/LambdaTeX/Action.hs b/src/Text/LaTeX/LambdaTeX/Action.hs
--- a/src/Text/LaTeX/LambdaTeX/Action.hs
+++ b/src/Text/LaTeX/LambdaTeX/Action.hs
@@ -1,12 +1,15 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Text.LaTeX.LambdaTeX.Action where
 
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- | Register an IO action (with a given name) that needs to be completed before the pdf can be built.
 --
 -- Use this to generate and build external resources that are included with @includegraphics@ for example.
-registerAction :: Monad m => String -- ^ Name of the job
-                          -> IO () -- ^ Job
-                          -> ΛTeXT m ()
-registerAction name func = λtell $ mempty { outputActions = [(name, func)] }
+registerAction ::
+       Monad m
+    => String -- ^ Name of the job
+    -> (FilePath -> IO ()) -- ^ Job, it takes the project directory as an argument
+    -> ΛTeXT m ()
+registerAction name func = λtell $ mempty {outputActions = [(name, func)]}
diff --git a/src/Text/LaTeX/LambdaTeX/Error.hs b/src/Text/LaTeX/LambdaTeX/Error.hs
--- a/src/Text/LaTeX/LambdaTeX/Error.hs
+++ b/src/Text/LaTeX/LambdaTeX/Error.hs
@@ -1,6 +1,6 @@
 module Text.LaTeX.LambdaTeX.Error where
 
-import           Data.Text (Text)
+import Data.Text (Text)
 
 data ΛError
     = ReferenceMissing Text
diff --git a/src/Text/LaTeX/LambdaTeX/Package.hs b/src/Text/LaTeX/LambdaTeX/Package.hs
--- a/src/Text/LaTeX/LambdaTeX/Package.hs
+++ b/src/Text/LaTeX/LambdaTeX/Package.hs
@@ -3,19 +3,23 @@
 -- Note: If you want different arguments to a package, you have to specify this by making a 'manual' 'packageDep' declaration before your document.
 module Text.LaTeX.LambdaTeX.Package where
 
-import           Text.LaTeX.Base.Syntax
+import Text.LaTeX.Base.Syntax
 
-import qualified Data.Set                           as S
+import qualified Data.Set as S
 
-import           Text.LaTeX.LambdaTeX.Package.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Package.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- | Declare a dependency to a package, with given arguments
-packageDep :: Monad m => [LaTeX] -- ^ Arguments
-                      -> Text -- ^ Name of the LaTeX package
-                      -> ΛTeXT m ()
-packageDep args name = λtell $ mempty { outputPackageDependencies = S.singleton (PackageDep name args) }
+packageDep ::
+       Monad m
+    => [LaTeX] -- ^ Arguments
+    -> Text -- ^ Name of the LaTeX package
+    -> ΛTeXT m ()
+packageDep args name =
+    λtell $
+    mempty {outputPackageDependencies = S.singleton (PackageDep name args)}
 
 -- | Declare a dependency to a package without any arguments
 packageDep_ :: Monad m => Text -> ΛTeXT m ()
-packageDep_ name = packageDep [] name
+packageDep_ = packageDep []
diff --git a/src/Text/LaTeX/LambdaTeX/Package/Internal.hs b/src/Text/LaTeX/LambdaTeX/Package/Internal.hs
--- a/src/Text/LaTeX/LambdaTeX/Package/Internal.hs
+++ b/src/Text/LaTeX/LambdaTeX/Package/Internal.hs
@@ -1,67 +1,73 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Text.LaTeX.LambdaTeX.Package.Internal where
 
-import           Control.Monad
-import           Data.List
+import Control.Monad
+import Data.List
 
-import           Text.LaTeX.Base.Syntax
+import Text.LaTeX.Base.Syntax
 
-import           Text.LaTeX.LambdaTeX.Package.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Package.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- | Inject package dependencies into a given LaTeX document.
 --   This is done by top-level functions in @Text.LaTeX.LambdaTeX@ automatically
 injectPackageDependencies :: [PackageDep] -> LaTeX -> Maybe LaTeX
 injectPackageDependencies packages latex = do
     ps <- reorderPackages packages
-    let packageDecs = mconcat $ map (\(PackageDep name args) -> usepackage args name) ps
+    let packageDecs =
+            mconcat $ map (\(PackageDep name args) -> usepackage args name) ps
     pure (inject packageDecs latex)
   where
     inject ps = go
-      where
         -- We're looking for this: TeXComm "documentclass" ...
         -- We have to go looking through the LaTeX :(
+      where
         go t@(TeXComm "documentclass" _) = TeXSeq t ps
         go (TeXSeq t1 t2) = TeXSeq (go t1) (go t2)
         go c = c
 
-
-
 reorderPackages :: [PackageDep] -> Maybe [PackageDep]
 reorderPackages deps = do
     bestEffort <- foldM (flip reorderToSatisfy) deps allPackageCombinationRules
     if all (`ruleIsSatisfied` bestEffort) allPackageCombinationRules
-    then Just bestEffort
-    else Nothing
+        then Just bestEffort
+        else Nothing
 
-data PackageRule
-    = PackageOrder Text Text
+data PackageRule =
+    PackageOrder Text
+                 Text
     deriving (Show, Eq)
 
 -- Yes it's dumb, but it works for now.
 reorderToSatisfy :: PackageRule -> [PackageDep] -> Maybe [PackageDep]
-reorderToSatisfy (PackageOrder n1 n2) ps = Just $
+reorderToSatisfy (PackageOrder n1 n2) ps =
+    Just $
     case (,) <$> elemIndex n1 names <*> elemIndex n2 names of
         Nothing -> ps
         Just (ix1, ix2) ->
             if ix1 < ix2
-            then ps
-            else (ps !! ix1)
-                : (ps !! ix2)
-                : map snd (filter (\(ix, _) -> ix /= ix1 && ix /= ix2) (zip [0..] ps))
-  where names = map packageDepName ps
+                then ps
+                else (ps !! ix1) :
+                     (ps !! ix2) :
+                     map
+                         snd
+                         (filter
+                              (\(ix, _) -> ix /= ix1 && ix /= ix2)
+                              (zip [0 ..] ps))
+  where
+    names = map packageDepName ps
 
 ruleIsSatisfied :: PackageRule -> [PackageDep] -> Bool
-ruleIsSatisfied (PackageOrder n1 n2) ps
-    = case (<) <$> elemIndex n1 names <*> elemIndex n2 names of
+ruleIsSatisfied (PackageOrder n1 n2) ps =
+    case (<) <$> elemIndex n1 names <*> elemIndex n2 names of
         Just False -> False
         _ -> True
-  where names = map packageDepName ps
+  where
+    names = map packageDepName ps
 
 allPackageCombinationRules :: [PackageRule]
-allPackageCombinationRules =
-    [ mintedLibertineRule
-    ]
+allPackageCombinationRules = [mintedLibertineRule]
 
 mintedLibertineRule :: PackageRule
 mintedLibertineRule = PackageOrder "minted" "libertine"
@@ -70,4 +76,3 @@
 --   Don't use this directly, use the packageDep instead!
 usepackage :: [LaTeX] -> Text -> LaTeX
 usepackage ls pn = TeXComm "usepackage" [MOptArg ls, FixArg $ TeXRaw pn]
-
diff --git a/src/Text/LaTeX/LambdaTeX/Package/Types.hs b/src/Text/LaTeX/LambdaTeX/Package/Types.hs
--- a/src/Text/LaTeX/LambdaTeX/Package/Types.hs
+++ b/src/Text/LaTeX/LambdaTeX/Package/Types.hs
@@ -1,14 +1,14 @@
 module Text.LaTeX.LambdaTeX.Package.Types where
 
-import           Data.Ord               (comparing)
-import           Data.Text              (Text)
+import Data.Ord (comparing)
+import Data.Text (Text)
 
-import           Text.LaTeX.Base.Syntax (LaTeX)
+import Text.LaTeX.Base.Syntax (LaTeX)
 
-data PackageDep = PackageDep {
-      packageDepName    :: Text
+data PackageDep = PackageDep
+    { packageDepName :: Text
     , packageDepOptions :: [LaTeX]
-  } deriving (Show, Eq)
+    } deriving (Show, Eq)
 
 instance Ord PackageDep where
     compare = comparing packageDepName
diff --git a/src/Text/LaTeX/LambdaTeX/Part.hs b/src/Text/LaTeX/LambdaTeX/Part.hs
--- a/src/Text/LaTeX/LambdaTeX/Part.hs
+++ b/src/Text/LaTeX/LambdaTeX/Part.hs
@@ -1,16 +1,16 @@
 module Text.LaTeX.LambdaTeX.Part where
 
-import           Data.Text (Text)
+import Data.Text (Text)
 
-newtype Part = Part { unPart :: [Text] }
-    deriving Show
+newtype Part = Part
+    { unPart :: [Text]
+    } deriving (Show)
 
 emptyPart :: Part
-emptyPart = Part { unPart = [] }
+emptyPart = Part {unPart = []}
 
 pushPart :: Part -> Text -> Part
-pushPart p t = Part { unPart = unPart p ++ [t] }
+pushPart p t = Part {unPart = unPart p ++ [t]}
 
 popPart :: Part -> Part
-popPart p = Part { unPart = init $ unPart p }
-
+popPart p = Part {unPart = init $ unPart p}
diff --git a/src/Text/LaTeX/LambdaTeX/Reference.hs b/src/Text/LaTeX/LambdaTeX/Reference.hs
--- a/src/Text/LaTeX/LambdaTeX/Reference.hs
+++ b/src/Text/LaTeX/LambdaTeX/Reference.hs
@@ -1,15 +1,16 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Text.LaTeX.LambdaTeX.Reference where
 
-import           Text.LaTeX.Base.Class
-import           Text.LaTeX.Base.Syntax
+import Text.LaTeX.Base.Class
+import Text.LaTeX.Base.Syntax
 
-import qualified Text.LaTeX.Base.Commands                as H (label, pageref,
-                                                               ref)
+import qualified Text.LaTeX.Base.Commands as H
+       (label, pageref, ref)
 
-import           Text.LaTeX.LambdaTeX.Reference.Internal
-import           Text.LaTeX.LambdaTeX.Reference.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Reference.Internal
+import Text.LaTeX.LambdaTeX.Reference.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- * Internal references
 -- An internal references point is defined by a label
@@ -17,9 +18,7 @@
 --
 -- ΛTeX automatically ensures that those references are always internally consistent
 -- BUT you have to make sure that you use these functions instead of the regular ones.
-
 -- ** Labels
-
 -- | Label a part
 label :: Monad m => Text -> ΛTeXT m ()
 label l = do
@@ -40,27 +39,24 @@
 
 -- * External references
 -- ** Defining references
-
 -- TODO(kerckhove) Check for duplicate fields?
-
 -- | Define an external reference.
 --   Use 'cite' or 'nocite' to use this in your document.
 makeReference :: ReferenceType -> Text -> [(Text, Text)] -> Reference
 makeReference = Reference
 
 -- ** Using references
-
 -- | Refer to an external reference.
 cite :: Monad m => Reference -> ΛTeXT m ()
-cite ref = do
-  fromLaTeX $ comm1 "cite" $ TeXRaw $ referenceName ref
-  addReference ref
+cite rf = do
+    fromLaTeX $ comm1 "cite" $ TeXRaw $ referenceName rf
+    addReference rf
 
 -- | Put an external reference in your list of references without using it.
 nocite :: Monad m => Reference -> ΛTeXT m ()
-nocite ref = do
-  fromLaTeX $ comm1 "nocite" $ TeXRaw $ referenceName ref
-  addReference ref
+nocite rf = do
+    fromLaTeX $ comm1 "nocite" $ TeXRaw $ referenceName rf
+    addReference rf
 
 -- ** Reference Types
 --
@@ -78,4 +74,3 @@
 
 article :: ReferenceType
 article = "article"
-
diff --git a/src/Text/LaTeX/LambdaTeX/Reference/Internal.hs b/src/Text/LaTeX/LambdaTeX/Reference/Internal.hs
--- a/src/Text/LaTeX/LambdaTeX/Reference/Internal.hs
+++ b/src/Text/LaTeX/LambdaTeX/Reference/Internal.hs
@@ -1,43 +1,42 @@
 {-# LANGUAGE OverloadedStrings #-}
+
 module Text.LaTeX.LambdaTeX.Reference.Internal where
 
-import qualified Data.Set                             as S
-import qualified Data.Text                            as T
+import qualified Data.Set as S
+import qualified Data.Text as T
 
-import           Text.LaTeX.LambdaTeX.Reference.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Reference.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- * Internal references
-
 -- | Declare that a label has been made
-addLabelMade ::  Monad m => Text -> ΛTeXT m ()
-addLabelMade label = λtell $ mempty { outputLabelsMade = S.singleton label }
+addLabelMade :: Monad m => Text -> ΛTeXT m ()
+addLabelMade label = λtell $ mempty {outputLabelsMade = S.singleton label}
 
 -- | Declare that a label is needed
-addLabelNeeded ::  Monad m => Text -> ΛTeXT m ()
-addLabelNeeded label = λtell $ mempty { outputLabelsNeeded = S.singleton label }
+addLabelNeeded :: Monad m => Text -> ΛTeXT m ()
+addLabelNeeded label = λtell $ mempty {outputLabelsNeeded = S.singleton label}
 
 -- * External references
-
 -- | Render references to bib(La)TeX format
 renderReferences :: [Reference] -> Text
-renderReferences rs = (`mappend` "\n\n") . T.intercalate ",\n\n" $ map showRef rs
+renderReferences rs =
+    (`mappend` "\n\n") . T.intercalate ",\n\n" $ map showRef rs
   where
     showRef :: Reference -> Text
-    showRef r = mconcat
-        [
-          "@"
-        , referenceType r
-        , "{"
-        , referenceName r
-        , ",\n"
-        , T.intercalate ",\n" (map showField $ referenceFields r)
-        , "\n}"
-        ]
-
+    showRef r =
+        mconcat
+            [ "@"
+            , referenceType r
+            , "{"
+            , referenceName r
+            , ",\n"
+            , T.intercalate ",\n" (map showField $ referenceFields r)
+            , "\n}"
+            ]
     showField :: (Text, Text) -> Text
     showField (a, b) = mconcat ["  ", a, " = {", b, "}"]
 
 -- | Add a reference to a ΛTeX generator
 addReference :: Monad m => Reference -> ΛTeXT m ()
-addReference ref = λtell $ mempty { outputExternalReferences = S.singleton ref }
+addReference ref = λtell $ mempty {outputExternalReferences = S.singleton ref}
diff --git a/src/Text/LaTeX/LambdaTeX/Reference/Types.hs b/src/Text/LaTeX/LambdaTeX/Reference/Types.hs
--- a/src/Text/LaTeX/LambdaTeX/Reference/Types.hs
+++ b/src/Text/LaTeX/LambdaTeX/Reference/Types.hs
@@ -1,16 +1,15 @@
 module Text.LaTeX.LambdaTeX.Reference.Types where
 
-import           Data.Ord  (comparing)
-import           Data.Text (Text)
+import Data.Ord (comparing)
+import Data.Text (Text)
 
 type ReferenceType = Text
-data Reference = Reference {
-      referenceType   :: ReferenceType
-    , referenceName   :: Text
+
+data Reference = Reference
+    { referenceType :: ReferenceType
+    , referenceName :: Text
     , referenceFields :: [(Text, Text)]
-  } deriving (Show, Eq)
+    } deriving (Show, Eq)
 
 instance Ord Reference where
     compare = comparing referenceName
-
-
diff --git a/src/Text/LaTeX/LambdaTeX/Selection.hs b/src/Text/LaTeX/LambdaTeX/Selection.hs
--- a/src/Text/LaTeX/LambdaTeX/Selection.hs
+++ b/src/Text/LaTeX/LambdaTeX/Selection.hs
@@ -1,15 +1,14 @@
 module Text.LaTeX.LambdaTeX.Selection where
 
-import           Control.Monad                           (when)
+import Control.Monad (when)
 
-import qualified Data.Text                               as T
+import qualified Data.Text as T
 
-import           Text.LaTeX.LambdaTeX.Selection.Internal
-import           Text.LaTeX.LambdaTeX.Selection.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Selection.Internal
+import Text.LaTeX.LambdaTeX.Selection.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- * Making selections
-
 -- | Construct a selection from a space-separated list of strings representing selectors
 --
 -- > constructSelection = map constructSelector . words
@@ -36,11 +35,10 @@
 constructSelector s = Match $ map T.pack $ split s
 
 -- * Using selections
-
 -- | Declare a sub-part of the document with a name.
 --   This allows you to use the subset-selection feature later.
 note :: Monad m => Text -> ΛTeXT m () -> ΛTeXT m ()
-note partname func = inPart partname $ do
-    s <- isSelected
-    when s func
-
+note partname func =
+    inPart partname $ do
+        s <- isSelected
+        when s func
diff --git a/src/Text/LaTeX/LambdaTeX/Selection/Internal.hs b/src/Text/LaTeX/LambdaTeX/Selection/Internal.hs
--- a/src/Text/LaTeX/LambdaTeX/Selection/Internal.hs
+++ b/src/Text/LaTeX/LambdaTeX/Selection/Internal.hs
@@ -1,9 +1,9 @@
 module Text.LaTeX.LambdaTeX.Selection.Internal where
 
-import           Data.List                            (isPrefixOf)
+import Data.List (isPrefixOf)
 
-import           Text.LaTeX.LambdaTeX.Selection.Types
-import           Text.LaTeX.LambdaTeX.Types
+import Text.LaTeX.LambdaTeX.Selection.Types
+import Text.LaTeX.LambdaTeX.Types
 
 -- | Whether a part is selected by a given list of selectors.
 --
@@ -12,18 +12,20 @@
 -- All parts are selected or
 -- It it is matched and not ignored.
 selects :: Part -> [Selector] -> Bool
-selects (Part ps) ss = go ps ss False
-    where
-        go :: [Text] -> [Selector] -> Bool -> Bool
-        go _ [] b                       = b
-        go ps (All:ss) _                = go ps ss True
-        go ps ((Match s):ss) b          = if (ps `isPrefixOf` s || s `isPrefixOf` ps)
-                                          then go ps ss True
-                                          else go ps ss b
-        go ps ((Ignore s):ss) True      = if s `isPrefixOf` ps
-                                          then go ps ss False
-                                          else go ps ss True
-        go ps ((Ignore _):ss) False     = go ps ss False
+selects (Part parts) selectors = go parts selectors False
+  where
+    go :: [Text] -> [Selector] -> Bool -> Bool
+    go _ [] b = b
+    go ps (All:ss) _ = go ps ss True
+    go ps (Match s:ss) b =
+        if ps `isPrefixOf` s || s `isPrefixOf` ps
+            then go ps ss True
+            else go ps ss b
+    go ps (Ignore s:ss) True =
+        if s `isPrefixOf` ps
+            then go ps ss False
+            else go ps ss True
+    go ps (Ignore _:ss) False = go ps ss False
 
 -- | Whether the current part is selected to be generated
 isSelected :: Monad m => ΛTeXT m Bool
@@ -33,7 +35,6 @@
     return $ selects part sels
 
 -- * Current part Helpers
-
 -- | Returns the current part from the ΛTeX state
 currentPart :: Monad m => ΛTeXT m Part
 currentPart = λgets stateCurrentPart
@@ -49,17 +50,18 @@
 --
 -- WARNING: This should never be used outside of 'inPart'
 pushCurrentPart :: Monad m => Text -> ΛTeXT m ()
-pushCurrentPart partname = λmodify (\s -> s { stateCurrentPart = pushPart (stateCurrentPart s) partname})
+pushCurrentPart partname =
+    λmodify
+        (\s -> s {stateCurrentPart = pushPart (stateCurrentPart s) partname})
 
 -- | Pop a part name off the current part stack
 --
 -- WARNING: This should never be used outside of 'inPart'
 popCurrentPart :: Monad m => ΛTeXT m ()
-popCurrentPart = λmodify (\s -> s { stateCurrentPart = popPart $ stateCurrentPart s })
-
+popCurrentPart =
+    λmodify (\s -> s {stateCurrentPart = popPart $ stateCurrentPart s})
 
 -- * Text Helpers
-
 -- | Split a string on a dot.
 -- This can be useful to convert from a 'Selector's textual representation back to a selector
 --
@@ -69,11 +71,10 @@
 
 -- | Split a string on a specific character
 splitOn :: Char -> String -> [String]
-splitOn c s = go s []
+splitOn c str = go str []
   where
     go :: String -> String -> [String]
     go [] s = [s]
-    go (sc:ss) acc | sc == c   = acc : go ss []
-                   | otherwise = go ss (acc ++ [sc])
-
-
+    go (sc:ss) acc
+        | sc == c = acc : go ss []
+        | otherwise = go ss (acc ++ [sc])
diff --git a/src/Text/LaTeX/LambdaTeX/Selection/Types.hs b/src/Text/LaTeX/LambdaTeX/Selection/Types.hs
--- a/src/Text/LaTeX/LambdaTeX/Selection/Types.hs
+++ b/src/Text/LaTeX/LambdaTeX/Selection/Types.hs
@@ -1,10 +1,11 @@
 module Text.LaTeX.LambdaTeX.Selection.Types where
 
-import           Data.Text (Text)
+import Data.Text (Text)
 
 type Selection = [Selector]
-data Selector = All
-              | Match [Text]
-              | Ignore [Text]
-    deriving (Show, Eq)
 
+data Selector
+    = All
+    | Match [Text]
+    | Ignore [Text]
+    deriving (Show, Eq)
diff --git a/src/Text/LaTeX/LambdaTeX/Types.hs b/src/Text/LaTeX/LambdaTeX/Types.hs
--- a/src/Text/LaTeX/LambdaTeX/Types.hs
+++ b/src/Text/LaTeX/LambdaTeX/Types.hs
@@ -1,65 +1,54 @@
-{-# LANGUAGE CPP                        #-}
-{-# LANGUAGE FlexibleInstances          #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
 
-module Text.LaTeX.LambdaTeX.Types (
-      module Text.LaTeX.LambdaTeX.Types
+module Text.LaTeX.LambdaTeX.Types
+    ( module Text.LaTeX.LambdaTeX.Types
     , module Text.LaTeX.LambdaTeX.Part
     , module Text.LaTeX.LambdaTeX.Error
     , module Text.LaTeX.LambdaTeX.Package.Types
     , module Text.LaTeX.LambdaTeX.Reference.Types
     , module Text.LaTeX.LambdaTeX.Selection.Types
-
-#if !MIN_VERSION_base(4,8,0)
-    , module Control.Applicative
-    , module Data.Monoid
-#endif
     , Text
     ) where
 
-#if !MIN_VERSION_base(4,8,0)
-import           Control.Applicative
-import           Data.Monoid                          hiding (All)
-#endif
-
-import           Control.Monad                        (liftM)
-import           Control.Monad.IO.Class               (MonadIO, liftIO)
-import           Control.Monad.Reader                 (MonadReader (..), asks)
-import           Control.Monad.RWS                    (RWST (..))
-import           Control.Monad.State                  (MonadState (..), gets,
-                                                       modify)
-import           Control.Monad.Trans                  (MonadTrans (..), lift)
-import           Control.Monad.Writer                 (MonadWriter (..))
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Control.Monad.RWS (RWST(..))
+import Control.Monad.Reader (MonadReader(..), asks)
+import Control.Monad.State (MonadState(..), gets, modify)
+import Control.Monad.Trans (MonadTrans(..), lift)
+import Control.Monad.Writer (MonadWriter(..))
 
-import           Data.Set                             (Set)
-import qualified Data.Set                             as S
-import           Data.String                          (IsString (..))
-import           Data.Text                            (Text)
+import Data.Set (Set)
+import qualified Data.Set as S
+import Data.String (IsString(..))
+import Data.Text (Text)
 
-import           Text.LaTeX.Base                      (LaTeX, LaTeXT, runLaTeXT)
-import           Text.LaTeX.Base.Class                (LaTeXC (..), fromLaTeX)
-import           Text.LaTeX.Base.Writer               (extractLaTeX, textell)
+import Text.LaTeX.Base (LaTeX, LaTeXT, runLaTeXT)
+import Text.LaTeX.Base.Class (LaTeXC(..), fromLaTeX)
+import Text.LaTeX.Base.Writer (extractLaTeX, textell)
 
-import           Text.LaTeX.Packages.AMSMath          ()
+import Text.LaTeX.Packages.AMSMath ()
 
-import           Text.LaTeX.LambdaTeX.Error
-import           Text.LaTeX.LambdaTeX.Package.Types
-import           Text.LaTeX.LambdaTeX.Part
-import           Text.LaTeX.LambdaTeX.Reference.Types
-import           Text.LaTeX.LambdaTeX.Selection.Types
+import Text.LaTeX.LambdaTeX.Error
+import Text.LaTeX.LambdaTeX.Package.Types
+import Text.LaTeX.LambdaTeX.Part
+import Text.LaTeX.LambdaTeX.Reference.Types
+import Text.LaTeX.LambdaTeX.Selection.Types
 
 -- * The ΛTeX Monad
 type LambdaTeXT = ΛTeXT
+
 type LambdaTeXT_ m = ΛTeXT_ m
 
 type ΛTeXT_ m = ΛTeXT m ()
 
-newtype ΛTeXT m a =
-    ΛTeXT { unwrapΛTeXT :: LaTeXT (RWST ΛConfig ΛOutput ΛState m) a }
-    deriving (Functor, Applicative, Monad)
+newtype ΛTeXT m a = ΛTeXT
+    { unwrapΛTeXT :: LaTeXT (RWST ΛConfig ΛOutput ΛState m) a
+    } deriving (Functor, Applicative, Monad)
 
 -- TODO(kerckhove) Move and add amsmath dependency
 instance (Monad m, a ~ ()) => Num (ΛTeXT m a) where
@@ -72,16 +61,19 @@
     -- Non-defined methods
     signum = ΛTeXT . signum . unwrapΛTeXT
 
-
 -- TODO(kerckhove) Move and add amsmath dependency
 instance (Monad m, a ~ ()) => Fractional (ΛTeXT m a) where
     (/) a b = ΛTeXT $ unwrapΛTeXT a / unwrapΛTeXT b
     fromRational = fromLaTeX . fromRational
 
 -- TODO(kerckhove) Also instantiate floating?
-
-runΛTeX :: ΛTeXT m a -> ΛConfig -> ΛState -> m ((a, LaTeX), ΛState, ΛOutput)
-runΛTeX func conf state = runRWST (runLaTeXT $ unwrapΛTeXT func) conf state
+runΛTeX ::
+       Monad m
+    => ΛTeXT m a
+    -> ΛConfig
+    -> ΛState
+    -> m ((a, LaTeX), ΛState, ΛOutput)
+runΛTeX func = runRWST (runLaTeXT $ unwrapΛTeXT func)
 
 instance MonadTrans ΛTeXT where
     lift = ΛTeXT . lift . lift
@@ -122,64 +114,60 @@
 
 -- | This function run a 'LaTeXT' computation,
 -- lifting the result again in the monad.
-extractΛLaTeX :: Monad m => ΛTeXT m a -> ΛTeXT m (a,LaTeX)
+extractΛLaTeX :: Monad m => ΛTeXT m a -> ΛTeXT m (a, LaTeX)
 extractΛLaTeX = ΛTeXT . extractLaTeX . unwrapΛTeXT
 
 -- | Like 'extractΛLaTeX' but without the result
 extractΛLaTeX_ :: Monad m => ΛTeXT m a -> ΛTeXT m LaTeX
-extractΛLaTeX_ = liftM snd . extractΛLaTeX
+extractΛLaTeX_ = fmap snd . extractΛLaTeX
 
 -- | Internal ΛTeXT configration
-data ΛConfig    = ΛConfig {
-      configSelection :: Selection
+newtype ΛConfig = ΛConfig
+    { configSelection :: Selection
     }
 
 -- | Internal ΛTeXT configration output
-data ΛOutput    = ΛOutput {
-      outputPackageDependencies :: Set PackageDep
-    , outputExternalReferences  :: Set Reference
-    , outputLabelsMade          :: Set Text
-    , outputLabelsNeeded        :: Set Text
-    , outputActions             :: [(String, IO ())]
+data ΛOutput = ΛOutput
+    { outputPackageDependencies :: Set PackageDep
+    , outputExternalReferences :: Set Reference
+    , outputLabelsMade :: Set Text
+    , outputLabelsNeeded :: Set Text
+    , outputActions :: [(String, FilePath -> IO ())]
     }
 
 instance Monoid ΛOutput where
-    mempty = ΛOutput {
-            outputPackageDependencies   = S.empty
-          , outputExternalReferences    = S.empty
-          , outputLabelsMade            = S.empty
-          , outputLabelsNeeded          = S.empty
-          , outputActions               = []
+    mempty =
+        ΛOutput
+        { outputPackageDependencies = S.empty
+        , outputExternalReferences = S.empty
+        , outputLabelsMade = S.empty
+        , outputLabelsNeeded = S.empty
+        , outputActions = []
         }
-
-    mappend o1 o2 = ΛOutput {
-            outputPackageDependencies =
-                S.union
-                    (outputPackageDependencies o1)
-                    (outputPackageDependencies o2)
-          , outputExternalReferences =
-                S.union
-                    (outputExternalReferences o1)
-                    (outputExternalReferences o2)
-          , outputLabelsMade =
-                S.union
-                    (outputLabelsMade o1)
-                    (outputLabelsMade o2)
-          , outputLabelsNeeded =
-                S.union
-                    (outputLabelsNeeded o1)
-                    (outputLabelsNeeded o2)
-          , outputActions = outputActions o1 ++ outputActions o2
+    mappend o1 o2 =
+        ΛOutput
+        { outputPackageDependencies =
+              S.union
+                  (outputPackageDependencies o1)
+                  (outputPackageDependencies o2)
+        , outputExternalReferences =
+              S.union
+                  (outputExternalReferences o1)
+                  (outputExternalReferences o2)
+        , outputLabelsMade = S.union (outputLabelsMade o1) (outputLabelsMade o2)
+        , outputLabelsNeeded =
+              S.union (outputLabelsNeeded o1) (outputLabelsNeeded o2)
+        , outputActions = outputActions o1 ++ outputActions o2
         }
 
 -- | Internal ΛTeXT configration state
-data ΛState = ΛState {
-      stateCurrentPart :: Part
+newtype ΛState = ΛState
+    { stateCurrentPart :: Part
     }
 
 -- Orphan Monad Transformer instances for LaTeXT
 instance MonadReader r m => MonadReader r (LaTeXT m) where
-    ask   = lift ask
+    ask = lift ask
     local = local
     reader = lift . reader
 
@@ -193,10 +181,9 @@
     listen = listen
     pass = pass
 
-
 -- Monad Transformer instances for ΛTeXT
 instance MonadReader r m => MonadReader r (ΛTeXT m) where
-    ask   = lift ask
+    ask = lift ask
     local = local
     reader = lift . reader
 
@@ -209,4 +196,3 @@
     tell = lift . tell
     listen = listen
     pass = pass
-
diff --git a/src/Text/LaTeX/LambdaTeX/Utils.hs b/src/Text/LaTeX/LambdaTeX/Utils.hs
--- a/src/Text/LaTeX/LambdaTeX/Utils.hs
+++ b/src/Text/LaTeX/LambdaTeX/Utils.hs
@@ -1,14 +1,14 @@
 -- | ΛTeX utilities
 module Text.LaTeX.LambdaTeX.Utils where
 
-import           Control.Exception
-import           System.Directory  (removeFile)
-import           System.IO.Error   (isDoesNotExistError)
+import Control.Exception
+import System.Directory (removeFile)
+import System.IO.Error (isDoesNotExistError)
 
 -- | Remove the given file if it exists
 removeIfExists :: FilePath -> IO ()
 removeIfExists fileName = removeFile fileName `catch` handleExists
-  where handleExists e
-          | isDoesNotExistError e = return ()
-          | otherwise = throwIO e
-
+  where
+    handleExists e
+        | isDoesNotExistError e = return ()
+        | otherwise = throwIO e
diff --git a/test/MainTest.hs b/test/MainTest.hs
--- a/test/MainTest.hs
+++ b/test/MainTest.hs
@@ -1,9 +1,10 @@
 {-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+
 module MainTest where
 
 import qualified Spec
-import           Test.Hspec.Formatters
-import           Test.Hspec.Runner
+import Test.Hspec.Formatters
+import Test.Hspec.Runner
 
 main :: IO ()
 main = hspecWith defaultConfig {configFormatter = Just progress} Spec.spec
diff --git a/test/Text/LaTeX/LambdaTeX/Part/Arbitrary.hs b/test/Text/LaTeX/LambdaTeX/Part/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/LaTeX/LambdaTeX/Part/Arbitrary.hs
@@ -0,0 +1,11 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Text.LaTeX.LambdaTeX.Part.Arbitrary where
+
+import Test.QuickCheck
+
+import Data.Text.Arbitrary ()
+import Text.LaTeX.LambdaTeX.Part
+
+instance Arbitrary Part where
+    arbitrary = Part <$> arbitrary
diff --git a/test/Text/LaTeX/LambdaTeX/Selection/Arbitrary.hs b/test/Text/LaTeX/LambdaTeX/Selection/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/LaTeX/LambdaTeX/Selection/Arbitrary.hs
@@ -0,0 +1,11 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Text.LaTeX.LambdaTeX.Selection.Arbitrary where
+
+import Test.QuickCheck
+
+import Data.Text.Arbitrary ()
+import Text.LaTeX.LambdaTeX.Selection.Types
+
+instance Arbitrary Selector where
+    arbitrary = oneof [pure All, Match <$> arbitrary, Ignore <$> arbitrary]
diff --git a/test/Text/LaTeX/LambdaTeX/Selection/InternalSpec.hs b/test/Text/LaTeX/LambdaTeX/Selection/InternalSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Text/LaTeX/LambdaTeX/Selection/InternalSpec.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Text.LaTeX.LambdaTeX.Selection.InternalSpec where
+
+import Test.Hspec
+import Test.QuickCheck
+
+import Text.LaTeX.LambdaTeX.Part
+import Text.LaTeX.LambdaTeX.Part.Arbitrary ()
+import Text.LaTeX.LambdaTeX.Selection
+import Text.LaTeX.LambdaTeX.Selection.Arbitrary ()
+import Text.LaTeX.LambdaTeX.Selection.Internal
+import Text.LaTeX.LambdaTeX.Selection.Types
+
+spec :: Spec
+spec =
+    describe "selects" $ do
+        it "is false for the empty selection" $
+            property $ \p -> selects p [] `shouldBe` False
+        it "is true for the 'match all' selection" $
+            property $ \p -> selects p [All] `shouldBe` True
+        it "is true for the empty part and this nonempty selection" $
+            selects emptyPart [Match ["part"]] `shouldBe` True
+        it "matches explicitly matched parts" $
+            property $ \p -> selects (Part p) [Match p] `shouldBe` True
+        it "ignore expicitly ignored parts" $
+            property $ \p -> selects (Part p) [All, Ignore p] `shouldBe` False
+        it "matches the right part for these simple test cases" $ do
+            let p = Part ["this", "part"]
+            selects p [Match ["this"]] `shouldBe` True
+            selects p [Match ["this", "part"]] `shouldBe` True
+            selects p [Match ["this", "part", "should"]] `shouldBe` True
+            selects p [Match ["this", "part", "should", "be"]] `shouldBe` True
+            selects p [Match ["this", "part", "should", "be", "matched"]] `shouldBe`
+                True
+            selects p [Match ["something"]] `shouldBe` False
+            selects p [Match ["something", "else"]] `shouldBe` False
+        it "ignores the right part for these simple test cases" $ do
+            let p = Part ["this", "part"]
+            selects p [All, Ignore ["this"]] `shouldBe` False
+            selects p [All, Ignore ["this", "part"]] `shouldBe` False
+            selects p [All, Ignore ["this", "part", "but", "it", "should"]] `shouldBe`
+                True
+            selects
+                p
+                [All, Ignore ["this", "part", "but", "it", "should", "be"]] `shouldBe`
+                True
+            selects
+                p
+                [ All
+                , Ignore
+                      ["this", "part", "but", "it", "should", "be", "matched"]
+                ] `shouldBe`
+                True
+        it
+            "constructs this selection that's more than three subparts long correctly" $
+            constructSelector "something.in.four.subparts" `shouldBe`
+            Match ["something", "in", "four", "subparts"]
