diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,17 @@
 # Changelog for ELynx
 
 
+## Version 0.3.1; in development
+
+
+## Version 0.3.0
+
+-   **`elynx-nexus`:** library to import and export Nexus files.
+-   **`elynx-tree`:** major refactor and big cleanup; use rose trees with branch
+    labels.
+-   **`elynx-tree`:** provide zippers.
+
+
 ## Version 0.2.2
 
 -   Validation and repetition of previous analyses is finally possible with the
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,9 +2,11 @@
 
 # The ELynx Suite
 
-Version: 0.2.2.
+Version: 0.3.0.
 Reproducible evolution made easy.
 
+<p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>
+
 A Haskell library and tool set for computational biology. The goal of ELynx is
 reproducible research. Evolutionary sequences and phylogenetic trees can be
 read, viewed, modified and simulated. The command line with all arguments is
@@ -12,11 +14,12 @@
 sums so that validation of past analyses is possible without the need to
 recompute the result.
 
-The Elynx Suite consists of four library packages and three executables providing
-a range of sub commands.
+The Elynx Suite consists of library packages and executables providing a range
+of sub commands.
 
 The library packages are:
 
+-   **elynx-nexus:** Nexus file support.
 -   **elynx-markov:** Simulate multi sequence alignments along phylogenetic trees.
 -   **elynx-seq:** Handle evolutionary sequences and multi sequence alignments.
 -   **elynx-tools:** Tools for the provided executables.
@@ -43,7 +46,7 @@
 
 2.  Clone the ELynx repository.
     
-        git clone clone https://github.com/dschrempf/elynx
+        git clone https://github.com/dschrempf/elynx
 
 3.  Navigate to the newly created `elynx` folder and build the binaries.
     This will take a while.
@@ -62,15 +65,34 @@
     [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable. Then, they can be used directly.
 
 
+# Documentation
+
+Documentation is available on [Hackage](https://hackage.haskell.org/).
+
+Libraries:
+
+-   [elynx-nexus](https://hackage.haskell.org/package/elynx-nexus)
+-   [elynx-markov](https://hackage.haskell.org/package/elynx-markov)
+-   [elynx-seq](https://hackage.haskell.org/package/elynx-seq)
+-   [elynx-tools](https://hackage.haskell.org/package/elynx-tools)
+-   [elynx-tree](https://hackage.haskell.org/package/elynx-tree)
+
+Executables:
+
+-   [elynx](https://hackage.haskell.org/package/elynx)
+-   [slynx](https://hackage.haskell.org/package/slynx)
+-   [tlynx](https://hackage.haskell.org/package/tlynx)
+
+
 # SLynx
 
 Handle evolutionary sequences.
 
-    slynx --help
+    slynx --help | head -n -16
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -95,6 +117,7 @@
       sub-sample               Sub-sample columns from multi sequence alignments.
       translate                Translate from DNA to Protein or DNAX to ProteinX.
     
+    
     Available sequence file formats:
       - FASTA
     
@@ -105,23 +128,6 @@
       - Protein (amino acids)
       - ProteinX (amino acids; including gaps)
       - ProteinS (amino acids; including gaps, and translation stops)
-      - ProteinI (amino acids; including gaps, translation stops, and IUPAC codes)
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Concatenate
@@ -130,9 +136,9 @@
 
     slynx concatenate --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE
       Concatenate sequences found in input files.
@@ -143,23 +149,6 @@
       -a,--alphabet NAME       Specify alphabet type NAME
       INPUT-FILE               Read sequences from INPUT-FILE
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Examine
@@ -168,9 +157,9 @@
 
     slynx examine --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site]
       Examine sequences. If data is a multi sequence alignment, additionally analyze columns.
@@ -182,23 +171,6 @@
       INPUT-FILE               Read sequences from INPUT-FILE
       --per-site               Report per site summary statistics
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Filter
@@ -207,9 +179,9 @@
 
     slynx filter-rows --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] 
                              [--shorter-than LENGTH] [--standard-characters]
@@ -225,31 +197,14 @@
       --standard-characters    Only keep sequences containing at least one standard
                                (i.e., non-IUPAC) character
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 Filter columns of multi sequence alignments with `filter-columns`.
 
     slynx filter-columns --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE 
                                 [--standard-chars DOUBLE]
@@ -263,23 +218,6 @@
       --standard-chars DOUBLE  Keep columns with a proportion standard (non-IUPAC)
                                characters larger than DOUBLE in [0,1]
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Simulate
@@ -288,9 +226,9 @@
 
     slynx simulate --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] 
                           [-m|--mixture-model MODEL] [-e|--edm-file NAME] 
@@ -352,27 +290,13 @@
        where XX is 10, 20, 30, 40, 50, or 60; CXX models, Quang et al., 2008.
     -m "EDM(EXCHANGEABILITIES)"
        Arbitrary empirical distribution mixture (EDM) models.
-       Stationary distributions have to be provided with the -e option.
+       Stationary distributions have to be provided with the -e or -p option.
        For example,
          LG exchangeabilities with stationary distributions given in FILE.
          -m "EDM(LG-Custom)" -e FILE
+         LG exchangeabilities with site profiles (Phylobayes) given in FILES.
+         -m "EDM(LG-Custom)" -p FILES
     For special mixture models, mixture weights are optional.
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Sub-sample
@@ -381,9 +305,9 @@
 
     slynx sub-sample --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE
                             (-n|--number-of-sites INT)
@@ -403,22 +327,6 @@
       -h,--help                Show this help text
     
     Create a given number of multi sequence alignments, each of which contains a given number of random sites drawn from the original multi sequence alignment.
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Translate
@@ -427,9 +335,9 @@
 
     slynx translate --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT)
                            (-u|--universal-code CODE)
@@ -444,34 +352,17 @@
       -u,--universal-code CODE universal code; one of: Standard,
                                VertebrateMitochondrial.
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 # TLynx
 
 Handle phylogenetic trees in Newick format.
 
-    tlynx --help
+    tlynx --help | head -n -16
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -496,26 +387,10 @@
       shuffle                  Shuffle a phylogenetic tree (keep coalescent times, but shuffle topology and leaves).
       simulate                 Simulate phylogenetic trees using birth and death processes (see also the 'coalesce' command for simulations using the coalescent process).
     
+    
     Available tree file formats:
       - Newick Standard: Branch support values are stored in square brackets after branch lengths.
       - Newick IqTree:   Branch support values are stored as node names after the closing bracket of forests.
-      - Newick RevBayes  Key-value pairs is provided in square brackets after node names as well as branch lengths. XXX: Key value pairs are IGNORED at the moment.
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Compare
@@ -524,12 +399,12 @@
 
     tlynx compare --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] 
-                         [-f|--newick-format FORMAT] NAME
+                         [-f|--newick-format FORMAT] NAMES
       Compare two phylogenetic trees (compute distances and branch-wise differences).
     
     Available options:
@@ -540,27 +415,11 @@
       -t,--intersect           Compare intersections; i.e., before comparison, drop
                                leaves that are not present in the other tree
       -f,--newick-format FORMAT
-                               Newick tree format; see 'tlynx
-                               --help' (default: Standard)
-      NAME                     Tree file
+                               Newick tree format: Standard, IqTree, or RevBayes;
+                               default: Standard; for detailed help, see 'tlynx
+                               --help'
+      NAMES                    Tree files
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Examine
@@ -569,9 +428,9 @@
 
     tlynx examine --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT]
       Compute summary statistics of phylogenetic trees.
@@ -581,26 +440,10 @@
       -V,--version             Show version
       INPUT-FILE               Read trees from INPUT-FILE
       -f,--newick-format FORMAT
-                               Newick tree format; see 'tlynx
-                               --help' (default: Standard)
+                               Newick tree format: Standard, IqTree, or RevBayes;
+                               default: Standard; for detailed help, see 'tlynx
+                               --help'
       -h,--help                Show this help text
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 ## Simulate
@@ -609,9 +452,9 @@
 
     tlynx simulate --help
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE] 
                           [-M|--condition-on-mrca] [-l|--lambda DOUBLE] 
@@ -640,33 +483,17 @@
     Summary statistics only: only print (NumberOfExtantChildren BranchLength) pairs for each branch of each tree. The trees are separated by a newline character.
     Sub-sampling: simulate one big tree with n'=round(n/rho), n'>=n, leaves, and randomly sample sub-trees with n leaves. Hence, with rho=1.0, the same tree is reported over and over again.
     Gernhard, T. (2008). The conditioned reconstructed process. Journal of Theoretical Biology, 253(4), 769–778. http://doi.org/10.1016/j.jtbi.2008.04.005
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
 
 
 # ELynx
 
 Validate and (optionally) redo past ELynx analyses.
 
-    elynx --help
+    elynx --help | head -n -16
 
-    ELynx Suite version 0.2.1.
+    ELynx Suite version 0.3.0.
     Developed by Dominik Schrempf.
-    Compiled on April 27, 2020, at 12:08 pm, UTC.
+    Compiled on July 30, 2020, at 12:40 pm, UTC.
     
     Usage: elynx COMMAND
       Validate and redo past ELynx analyses
@@ -678,37 +505,4 @@
     Available commands:
       validate                 Validate an ELynx analysis
       redo                     Redo an ELynx analysis
-    
-    
-    ELynx
-    -----
-    A Haskell library and tool set for computational biology. The goal of ELynx is
-    reproducible research. Evolutionary sequences and phylogenetic trees can be
-    read, viewed, modified and simulated. The command line with all arguments is
-    logged consistently, and automatically. Data integrity is verified using SHA256
-    sums so that validation of past analyses is possible without the need to
-    recompute the result.
-    
-    slynx     Analyze, modify, and simulate evolutionary sequences.
-    tlynx     Analyze, modify, and simulate phylogenetic trees.
-    elynx     Validate and redo past analyses.
-    
-    Get help for sub commands:
-      slynx examine --help
-
-
-# Library documentation
-
-Documentation of the libraries can be found on [Hackage](https://hackage.haskell.org/):
-
--   [elynx-markov](https://hackage.haskell.org/package/elynx-markov)
--   [elynx-seq](https://hackage.haskell.org/package/elynx-seq)
--   [elynx-tools](https://hackage.haskell.org/package/elynx-tools)
--   [elynx-tree](https://hackage.haskell.org/package/elynx-tree)
-
-Documentation of the executables is also available:
-
--   [elynx](https://hackage.haskell.org/package/elynx)
--   [slynx](https://hackage.haskell.org/package/slynx)
--   [tlynx](https://hackage.haskell.org/package/tlynx)
 
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,20 +1,17 @@
-{- |
-Module      :  Main
-Description :  Work with molecular sequence data
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Thu Sep  5 21:53:07 2019.
-
--}
-
+-- |
+-- Module      :  Main
+-- Description :  Work with molecular sequence data
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Thu Sep  5 21:53:07 2019.
 module Main where
 
-import           SLynx.SLynx
+import SLynx.SLynx
 
 main :: IO ()
 main = rSLynx
diff --git a/slynx.cabal b/slynx.cabal
--- a/slynx.cabal
+++ b/slynx.cabal
@@ -1,89 +1,87 @@
-cabal-version: 1.12
-name: slynx
-version: 0.2.2
-license: GPL-3
-license-file: LICENSE
-copyright: Dominik Schrempf (2020)
-maintainer: dominik.schrempf@gmail.com
-author: Dominik Schrempf
-homepage: https://github.com/dschrempf/elynx#readme
-bug-reports: https://github.com/dschrempf/elynx/issues
-synopsis: Handle molecular sequences
-description:
-    Examine, modify, and simulate molecular sequences in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
-category: Bioinformatics
-build-type: Simple
+cabal-version: 2.2
+
+-- This file has been generated from package.yaml by hpack version 0.34.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 826b98c0606c81f3576251bedb9ae6aa528a2afeb1a782a01a6f17578ce698af
+
+name:           slynx
+version:        0.3.0
+synopsis:       Handle molecular sequences
+description:    Examine, modify, and simulate molecular sequences in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
+category:       Bioinformatics
+homepage:       https://github.com/dschrempf/elynx#readme
+bug-reports:    https://github.com/dschrempf/elynx/issues
+author:         Dominik Schrempf
+maintainer:     dominik.schrempf@gmail.com
+copyright:      Dominik Schrempf (2020)
+license:        GPL-3.0-or-later
+license-file:   LICENSE
+build-type:     Simple
 extra-source-files:
     README.md
     ChangeLog.md
 
 source-repository head
-    type: git
-    location: https://github.com/dschrempf/elynx
+  type: git
+  location: https://github.com/dschrempf/elynx
 
 library
-    exposed-modules:
-        SLynx.Concatenate.Concatenate
-        SLynx.Concatenate.Options
-        SLynx.Examine.Examine
-        SLynx.Examine.Options
-        SLynx.Filter.Filter
-        SLynx.Filter.Options
-        SLynx.Options
-        SLynx.Simulate.Options
-        SLynx.Simulate.PhyloModel
-        SLynx.Simulate.Simulate
-        SLynx.SLynx
-        SLynx.SubSample.Options
-        SLynx.SubSample.SubSample
-        SLynx.Tools
-        SLynx.Translate.Options
-        SLynx.Translate.Translate
-    hs-source-dirs: src
-    other-modules:
-        Paths_slynx
-    default-language: Haskell2010
-    ghc-options: -Wall -fllvm
-    build-depends:
-        async >=2.2.2 && <2.3,
-        base >=4.13.0.0 && <4.14,
-        bytestring >=0.10.10.0 && <0.11,
-        containers >=0.6.2.1 && <0.7,
-        elynx-markov >=0.2.2 && <0.3,
-        elynx-seq >=0.2.1 && <0.3,
-        elynx-tools >=0.2.2 && <0.3,
-        elynx-tree >=0.2.2 && <0.3,
-        hmatrix >=0.20.0.0 && <0.21,
-        megaparsec >=8.0.0 && <8.1,
-        monad-logger >=0.3.32 && <0.4,
-        mwc-random >=0.14.0.0 && <0.15,
-        optparse-applicative >=0.15.1.0 && <0.16,
-        scientific >=0.3.6.2 && <0.4,
-        text >=1.2.4.0 && <1.3,
-        transformers >=0.5.6.2 && <0.6,
-        vector >=0.12.1.2 && <0.13
+  exposed-modules:
+      SLynx.Concatenate.Concatenate
+      SLynx.Concatenate.Options
+      SLynx.Examine.Examine
+      SLynx.Examine.Options
+      SLynx.Filter.Filter
+      SLynx.Filter.Options
+      SLynx.Options
+      SLynx.Simulate.Options
+      SLynx.Simulate.PhyloModel
+      SLynx.Simulate.Simulate
+      SLynx.SLynx
+      SLynx.SubSample.Options
+      SLynx.SubSample.SubSample
+      SLynx.Tools
+      SLynx.Translate.Options
+      SLynx.Translate.Translate
+  other-modules:
+      Paths_slynx
+  autogen-modules:
+      Paths_slynx
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -fllvm
+  build-depends:
+      async
+    , base >=4.7 && <5
+    , bytestring
+    , containers
+    , elynx-markov
+    , elynx-seq
+    , elynx-tools
+    , elynx-tree
+    , hmatrix
+    , megaparsec
+    , monad-logger
+    , mwc-random
+    , optparse-applicative
+    , scientific
+    , text
+    , transformers
+    , vector
+  default-language: Haskell2010
 
 executable slynx
-    main-is: Main.hs
-    hs-source-dirs: app
-    other-modules:
-        Paths_slynx
-    default-language: Haskell2010
-    ghc-options: -Wall -fllvm -threaded -rtsopts -with-rtsopts=-N
-    build-depends:
-        async >=2.2.2 && <2.3,
-        base >=4.13.0.0 && <4.14,
-        bytestring >=0.10.10.0 && <0.11,
-        containers >=0.6.2.1 && <0.7,
-        elynx-seq >=0.2.1 && <0.3,
-        elynx-tools >=0.2.2 && <0.3,
-        hmatrix >=0.20.0.0 && <0.21,
-        megaparsec >=8.0.0 && <8.1,
-        monad-logger >=0.3.32 && <0.4,
-        mwc-random >=0.14.0.0 && <0.15,
-        optparse-applicative >=0.15.1.0 && <0.16,
-        scientific >=0.3.6.2 && <0.4,
-        slynx -any,
-        text >=1.2.4.0 && <1.3,
-        transformers >=0.5.6.2 && <0.6,
-        vector >=0.12.1.2 && <0.13
+  main-is: Main.hs
+  other-modules:
+      Paths_slynx
+  hs-source-dirs:
+      app
+  ghc-options: -Wall -fllvm -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , elynx-seq
+    , elynx-tools
+    , slynx
+  default-language: Haskell2010
diff --git a/src/SLynx/Concatenate/Concatenate.hs b/src/SLynx/Concatenate/Concatenate.hs
--- a/src/SLynx/Concatenate/Concatenate.hs
+++ b/src/SLynx/Concatenate/Concatenate.hs
@@ -1,34 +1,29 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  Analyze.Analyze
-Description :  Parse sequence file formats and analyze them
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Oct  5 08:41:05 2018.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  Analyze.Analyze
+-- Description :  Parse sequence file formats and analyze them
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Oct  5 08:41:05 2018.
 module SLynx.Concatenate.Concatenate
-  ( concatenateCmd
+  ( concatenateCmd,
   )
 where
 
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Reader     ( ask )
-
-import           SLynx.Concatenate.Options
-import           SLynx.Tools
-
-import qualified ELynx.Data.Sequence.Sequence  as S
-import           ELynx.Export.Sequence.Fasta
-import           ELynx.Tools
+import Control.Monad.Logger
+import Control.Monad.Trans.Reader (ask)
+import qualified ELynx.Data.Sequence.Sequence as S
+import ELynx.Export.Sequence.Fasta
+import ELynx.Tools
+import SLynx.Concatenate.Options
+import SLynx.Tools
 
 -- | Concatenate sequences.
 concatenateCmd :: ELynx ConcatenateArguments ()
diff --git a/src/SLynx/Concatenate/Options.hs b/src/SLynx/Concatenate/Options.hs
--- a/src/SLynx/Concatenate/Options.hs
+++ b/src/SLynx/Concatenate/Options.hs
@@ -1,37 +1,33 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Concatenate.Options
-Description :  ELynxSeq argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
--}
-
+-- |
+-- Module      :  SLynx.Concatenate.Options
+-- Description :  ELynxSeq argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
 module SLynx.Concatenate.Options
-  ( ConcatenateArguments(..)
-  , concatenateArguments
+  ( ConcatenateArguments (..),
+    concatenateArguments,
   )
 where
 
-import           Control.Applicative
-import           Options.Applicative
-
-import           SLynx.Tools
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Tools
+import Control.Applicative
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Tools
 
 -- | Arguments needed to concatenate multi sequence alignments.
 data ConcatenateArguments = ConcatenateArguments
-    { ccAlphabet :: Alphabet
-    , ccInFiles  :: [FilePath] }
+  { ccAlphabet :: Alphabet,
+    ccInFiles :: [FilePath]
+  }
   deriving (Eq, Show, Generic)
 
 instance Reproducible ConcatenateArguments where
@@ -39,9 +35,9 @@
   outSuffixes _ = [".fasta"]
   getSeed _ = Nothing
   setSeed = const
-  parser  = concatenateArguments
+  parser = concatenateArguments
   cmdName = "concatenate"
-  cmdDsc  = ["Concatenate sequences found in input files."]
+  cmdDsc = ["Concatenate sequences found in input files."]
 
 instance FromJSON ConcatenateArguments
 
diff --git a/src/SLynx/Examine/Examine.hs b/src/SLynx/Examine/Examine.hs
--- a/src/SLynx/Examine/Examine.hs
+++ b/src/SLynx/Examine/Examine.hs
@@ -1,131 +1,128 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-
-Module      :  Analyze.Analyze
-Description :  Parse sequence file formats and analyze them
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Oct  5 08:41:05 2018.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+--
+-- Module      :  Analyze.Analyze
+-- Description :  Parse sequence file formats and analyze them
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Oct  5 08:41:05 2018.
 module SLynx.Examine.Examine
-  ( examineCmd
+  ( examineCmd,
   )
 where
 
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Reader     ( ask )
-import qualified Data.ByteString.Lazy.Char8    as L
-import qualified Data.Set                      as S
-import           Text.Printf
-
-import           SLynx.Examine.Options
-import           SLynx.Tools
-
-import qualified ELynx.Data.Alphabet.Alphabet  as A
+import Control.Monad.Logger
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.Set as S
+import qualified ELynx.Data.Alphabet.Alphabet as A
 import qualified ELynx.Data.Alphabet.Character as C
 import qualified ELynx.Data.Sequence.Alignment as M
-import qualified ELynx.Data.Sequence.Sequence  as Seq
-import           ELynx.Tools
+import qualified ELynx.Data.Sequence.Sequence as Seq
+import ELynx.Tools
+import SLynx.Examine.Options
+import SLynx.Tools
+import Text.Printf
 
 pRow :: String -> String -> L.ByteString
 pRow name val = alignLeft 50 n <> alignRight 10 v
- where
-  n = L.pack name
-  v = L.pack val
+  where
+    n = L.pack name
+    v = L.pack val
 
 examineAlignment :: Bool -> M.Alignment -> L.ByteString
 examineAlignment perSiteFlag a =
   L.unlines
-      [ L.pack
-        "Sequences have equal length (multi sequence alignment, or single sequence)."
-      , pRow "Total number of columns in alignment:" $ show (M.length a)
-      , pRow "Number of columns without gaps:" $ show (M.length aNoGaps)
-      , pRow "Number of columns with standard characters only:"
-        $ show (M.length aOnlyStd)
-      , L.empty
-      , pRow "Total number of characters:" $ show nTot
-      , pRow "Standard (i.e., not extended IUPAC) characters:"
-        $ show (nTot - nIUPAC - nGaps - nUnknowns)
-      , pRow "Extended IUPAC characters:" $ show nIUPAC
-      , pRow "Gaps:" $ show nGaps
-      , pRow "Unknowns:" $ show nUnknowns
-      , L.empty
-      , pRow "Percentage of standard characters:"
-        $ printf "%2.2f" (100.0 - percentIUPAC - percentGaps - percentUnknowns)
-      , pRow "Percentage of extended IUPAC characters:"
-        $ printf "%2.2f" percentIUPAC
-      , pRow "Percentage of gaps:" $ printf "%2.2f" percentGaps
-      , pRow "Percentage of unknowns:" $ printf "%2.2f" percentUnknowns
-      , L.empty
-      , L.pack "Distribution of characters:"
-              -- Holy crap.
-      , L.pack
-      $ concatMap ((: "     ") . C.toChar)
-      $ S.toList
-      $ A.std
-      $ A.alphabetSpec
-      $ M.alphabet a
-      , L.pack $ unwords $ map (printf "%.3f") charFreqs
-      , L.empty
-      , L.pack "Mean effective number of states (measured using entropy):"
-      , pRow "Across whole alignment:" $ printf "%.3f" kEffMean
-      , pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGaps
-      , pRow "Across columns without extended IUPAC characters:"
-        $ printf "%.3f" kEffMeanOnlyStd
-      , L.empty
-      , L.pack "Mean effective number of states (measured using homoplasy):"
-      , pRow "Across whole alignment:" $ printf "%.3f" kEffMeanHomo
-      , pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGapsHomo
-      , pRow "Across columns without extended IUPAC characters:"
-        $ printf "%.3f" kEffMeanOnlyStdHomo
-      ]
+    [ L.pack
+        "Sequences have equal length (multi sequence alignment, or single sequence).",
+      pRow "Total number of columns in alignment:" $ show (M.length a),
+      pRow "Number of columns without gaps:" $ show (M.length aNoGaps),
+      pRow "Number of columns with standard characters only:" $
+        show (M.length aOnlyStd),
+      L.empty,
+      pRow "Total number of characters:" $ show nTot,
+      pRow "Standard (i.e., not extended IUPAC) characters:" $
+        show (nTot - nIUPAC - nGaps - nUnknowns),
+      pRow "Extended IUPAC characters:" $ show nIUPAC,
+      pRow "Gaps:" $ show nGaps,
+      pRow "Unknowns:" $ show nUnknowns,
+      L.empty,
+      pRow "Percentage of standard characters:" $
+        printf "%2.2f" (100.0 - percentIUPAC - percentGaps - percentUnknowns),
+      pRow "Percentage of extended IUPAC characters:" $
+        printf "%2.2f" percentIUPAC,
+      pRow "Percentage of gaps:" $ printf "%2.2f" percentGaps,
+      pRow "Percentage of unknowns:" $ printf "%2.2f" percentUnknowns,
+      L.empty,
+      L.pack "Distribution of characters:",
+      -- Holy crap.
+      L.pack $
+        concatMap ((: "     ") . C.toChar) $
+          S.toList $
+            A.std $
+              A.alphabetSpec $
+                M.alphabet a,
+      L.pack $ unwords $ map (printf "%.3f") charFreqs,
+      L.empty,
+      L.pack "Mean effective number of states (measured using entropy):",
+      pRow "Across whole alignment:" $ printf "%.3f" kEffMean,
+      pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGaps,
+      pRow "Across columns without extended IUPAC characters:" $
+        printf "%.3f" kEffMeanOnlyStd,
+      L.empty,
+      L.pack "Mean effective number of states (measured using homoplasy):",
+      pRow "Across whole alignment:" $ printf "%.3f" kEffMeanHomo,
+      pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGapsHomo,
+      pRow "Across columns without extended IUPAC characters:" $
+        printf "%.3f" kEffMeanOnlyStdHomo
+    ]
     <> perSiteBS
- where
-  nTot             = M.length a * M.nSequences a
-  nIUPAC           = M.countIUPACChars a
-  nGaps            = M.countGaps a
-  nUnknowns        = M.countUnknowns a
-  percentIUPAC     = 100 * fromIntegral nIUPAC / fromIntegral nTot :: Double
-  percentGaps      = 100 * fromIntegral nGaps / fromIntegral nTot :: Double
-  percentUnknowns  = 100 * fromIntegral nUnknowns / fromIntegral nTot :: Double
-  aNoGaps          = M.filterColsNoGaps a
-  aOnlyStd         = M.filterColsOnlyStd aNoGaps
-  charFreqsPerSite = M.toFrequencyData a
-  charFreqs        = M.distribution charFreqsPerSite
-  kEffs            = M.kEffEntropy charFreqsPerSite
-  kEffsNoGaps      = M.kEffEntropy . M.toFrequencyData $ aNoGaps
-  kEffsOnlyStd     = M.kEffEntropy . M.toFrequencyData $ aOnlyStd
-  kEffMean         = sum kEffs / fromIntegral (length kEffs)
-  kEffMeanNoGaps   = sum kEffsNoGaps / fromIntegral (length kEffsNoGaps)
-  kEffMeanOnlyStd  = sum kEffsOnlyStd / fromIntegral (length kEffsOnlyStd)
-  kEffsHomo        = M.kEffHomoplasy charFreqsPerSite
-  kEffsNoGapsHomo  = M.kEffHomoplasy . M.toFrequencyData $ aNoGaps
-  kEffsOnlyStdHomo = M.kEffHomoplasy . M.toFrequencyData $ aOnlyStd
-  kEffMeanHomo     = sum kEffsHomo / fromIntegral (length kEffsHomo)
-  kEffMeanNoGapsHomo =
-    sum kEffsNoGapsHomo / fromIntegral (length kEffsNoGapsHomo)
-  kEffMeanOnlyStdHomo =
-    sum kEffsOnlyStdHomo / fromIntegral (length kEffsOnlyStdHomo)
-  perSiteBS = if perSiteFlag
-    then L.unlines
-      [ L.pack "Effective number of used states per site:"
-      , L.pack . show $ kEffs
-      ]
-    else L.empty
+  where
+    nTot = M.length a * M.nSequences a
+    nIUPAC = M.countIUPACChars a
+    nGaps = M.countGaps a
+    nUnknowns = M.countUnknowns a
+    percentIUPAC = 100 * fromIntegral nIUPAC / fromIntegral nTot :: Double
+    percentGaps = 100 * fromIntegral nGaps / fromIntegral nTot :: Double
+    percentUnknowns = 100 * fromIntegral nUnknowns / fromIntegral nTot :: Double
+    aNoGaps = M.filterColsNoGaps a
+    aOnlyStd = M.filterColsOnlyStd aNoGaps
+    charFreqsPerSite = M.toFrequencyData a
+    charFreqs = M.distribution charFreqsPerSite
+    kEffs = M.kEffEntropy charFreqsPerSite
+    kEffsNoGaps = M.kEffEntropy . M.toFrequencyData $ aNoGaps
+    kEffsOnlyStd = M.kEffEntropy . M.toFrequencyData $ aOnlyStd
+    kEffMean = sum kEffs / fromIntegral (length kEffs)
+    kEffMeanNoGaps = sum kEffsNoGaps / fromIntegral (length kEffsNoGaps)
+    kEffMeanOnlyStd = sum kEffsOnlyStd / fromIntegral (length kEffsOnlyStd)
+    kEffsHomo = M.kEffHomoplasy charFreqsPerSite
+    kEffsNoGapsHomo = M.kEffHomoplasy . M.toFrequencyData $ aNoGaps
+    kEffsOnlyStdHomo = M.kEffHomoplasy . M.toFrequencyData $ aOnlyStd
+    kEffMeanHomo = sum kEffsHomo / fromIntegral (length kEffsHomo)
+    kEffMeanNoGapsHomo =
+      sum kEffsNoGapsHomo / fromIntegral (length kEffsNoGapsHomo)
+    kEffMeanOnlyStdHomo =
+      sum kEffsOnlyStdHomo / fromIntegral (length kEffsOnlyStdHomo)
+    perSiteBS =
+      if perSiteFlag
+        then
+          L.unlines
+            [ L.pack "Effective number of used states per site:",
+              L.pack . show $ kEffs
+            ]
+        else L.empty
 
 examine :: Bool -> [Seq.Sequence] -> L.ByteString
 examine perSiteFlag ss =
   Seq.summarizeSequences ss <> case M.fromSequences ss of
-    Left  _ -> L.empty
+    Left _ -> L.empty
     Right a -> L.pack "\n" <> examineAlignment perSiteFlag a
 
 -- | Examine sequences.
diff --git a/src/SLynx/Examine/Options.hs b/src/SLynx/Examine/Options.hs
--- a/src/SLynx/Examine/Options.hs
+++ b/src/SLynx/Examine/Options.hs
@@ -1,46 +1,43 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Examine.Options
-Description :  ELynxSeq argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
--}
-
+-- |
+-- Module      :  SLynx.Examine.Options
+-- Description :  ELynxSeq argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
 module SLynx.Examine.Options
-  ( ExamineArguments(..)
-  , examineArguments
+  ( ExamineArguments (..),
+    examineArguments,
   )
 where
 
-import           Options.Applicative
-
-import           SLynx.Tools
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Tools
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Tools
 
 -- | Arguments needed to examine sequences.
 data ExamineArguments = ExamineArguments
-    { exAlphabet :: Alphabet
-    , exInFile   :: FilePath
-    , exPerSite  :: Bool }
+  { exAlphabet :: Alphabet,
+    exInFile :: FilePath,
+    exPerSite :: Bool
+  }
   deriving (Eq, Show, Generic)
 
 instance Reproducible ExamineArguments where
   inFiles = pure . exInFile
   outSuffixes _ = [".out"]
   getSeed _ = Nothing
--- XXX: Probably throw error when seed is set.
+
+  -- XXX: Probably throw error when seed is set.
   setSeed = const
-  parser  = examineArguments
+  parser = examineArguments
   cmdName = "examine"
   cmdDsc =
     [ "Examine sequences. If data is a multi sequence alignment, additionally analyze columns."
diff --git a/src/SLynx/Filter/Filter.hs b/src/SLynx/Filter/Filter.hs
--- a/src/SLynx/Filter/Filter.hs
+++ b/src/SLynx/Filter/Filter.hs
@@ -1,47 +1,42 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  Analyze.Analyze
-Description :  Parse sequence file formats and analyze them
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Oct  5 08:41:05 2018.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  Analyze.Analyze
+-- Description :  Parse sequence file formats and analyze them
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Oct  5 08:41:05 2018.
 module SLynx.Filter.Filter
-  ( filterRowsCmd
-  , filterColsCmd
+  ( filterRowsCmd,
+    filterColsCmd,
   )
 where
 
-import           Control.Monad                  ( when )
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Reader     ( ask )
-import qualified Data.ByteString.Lazy.Char8    as L
-import           Data.Maybe                     ( fromMaybe )
-import qualified Data.Text                     as T
-
-import           SLynx.Filter.Options
-import           SLynx.Tools
-
+import Control.Monad (when)
+import Control.Monad.Logger
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.ByteString.Lazy.Char8 as L
+import Data.Maybe (fromMaybe)
+import qualified Data.Text as T
 import qualified ELynx.Data.Sequence.Alignment as M
-import qualified ELynx.Data.Sequence.Sequence  as S
-import           ELynx.Export.Sequence.Fasta
-import           ELynx.Tools
+import qualified ELynx.Data.Sequence.Sequence as S
+import ELynx.Export.Sequence.Fasta
+import ELynx.Tools
+import SLynx.Filter.Options
+import SLynx.Tools
 
 filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> L.ByteString
 filterRows ml ms std ss = sequencesToFasta $ compose filters ss
- where
-  filters' =
-    map (fromMaybe id) [S.filterLongerThan <$> ml, S.filterShorterThan <$> ms]
-  filters = if std then S.filterStandard : filters' else filters'
+  where
+    filters' =
+      map (fromMaybe id) [S.filterLongerThan <$> ml, S.filterShorterThan <$> ms]
+    filters = if std then S.filterStandard : filters' else filters'
 
 -- | Filter sequences.
 filterRowsCmd :: ELynx FilterRowsArguments ()
@@ -50,28 +45,28 @@
   $(logInfo) "Command: Filter sequences of a list of sequences."
   maybe
     (return ())
-    (\val ->
-      $(logInfo) $ T.pack $ "  Keep sequences longer than " <> show val <> "."
+    ( \val ->
+        $(logInfo) $ T.pack $ "  Keep sequences longer than " <> show val <> "."
     )
     long
   maybe
     (return ())
-    (\val ->
-      $(logInfo) $ T.pack $ "  Keep sequences shorter than " <> show val <> "."
+    ( \val ->
+        $(logInfo) $ T.pack $ "  Keep sequences shorter than " <> show val <> "."
     )
     short
-  when std
-    $ $(logInfo)
-        "  Keep sequences containing at least one standard (i.e., non-IUPAC) character."
+  when std $
+    $(logInfo)
+      "  Keep sequences containing at least one standard (i.e., non-IUPAC) character."
   ss <- readSeqs al inFile
   let result = filterRows long short std ss
   out "filtered sequences" result ".fasta"
 
 filterCols :: Maybe Double -> [S.Sequence] -> L.ByteString
 filterCols ms ss = sequencesToFasta . M.toSequences $ compose filters a
- where
-  a       = either error id (M.fromSequences ss)
-  filters = map (fromMaybe id) [M.filterColsStd <$> ms]
+  where
+    a = either error id (M.fromSequences ss)
+    filters = map (fromMaybe id) [M.filterColsStd <$> ms]
 
 -- | Filter columns.
 filterColsCmd :: ELynx FilterColsArguments ()
@@ -81,11 +76,11 @@
   case standard of
     Nothing -> return ()
     Just p ->
-      $(logInfo)
-        $  T.pack
-        $ "  Keep columns with a proportion of standard (non-IUPAC) characters larger than "
-        ++ show p
-        ++ "."
+      $(logInfo) $
+        T.pack $
+          "  Keep columns with a proportion of standard (non-IUPAC) characters larger than "
+            ++ show p
+            ++ "."
   ss <- readSeqs al inFile
   let result = filterCols standard ss
   out "filtered sequences" result ".fasta"
diff --git a/src/SLynx/Filter/Options.hs b/src/SLynx/Filter/Options.hs
--- a/src/SLynx/Filter/Options.hs
+++ b/src/SLynx/Filter/Options.hs
@@ -1,42 +1,38 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Filter.Options
-Description :  ELynxSeq argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
--}
-
+-- |
+-- Module      :  SLynx.Filter.Options
+-- Description :  ELynxSeq argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
 module SLynx.Filter.Options
-  ( FilterRowsArguments(..)
-  , FilterColsArguments(..)
-  , filterRowsArguments
-  , filterColsArguments
+  ( FilterRowsArguments (..),
+    FilterColsArguments (..),
+    filterRowsArguments,
+    filterColsArguments,
   )
 where
 
-import           Control.Applicative
-import           Options.Applicative
-
-import           SLynx.Tools
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Tools
+import Control.Applicative
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Tools
 
 -- | Arguments needed for filtering sequences.
 data FilterRowsArguments = FilterRowsArguments
-  { frAlphabet :: Alphabet
-  , frInFile   :: FilePath
-  , frLonger   :: Maybe Int
-  , frShorter  :: Maybe Int
-  , frStandard :: Bool }
+  { frAlphabet :: Alphabet,
+    frInFile :: FilePath,
+    frLonger :: Maybe Int,
+    frShorter :: Maybe Int,
+    frStandard :: Bool
+  }
   deriving (Eq, Show, Generic)
 
 instance Reproducible FilterRowsArguments where
@@ -44,9 +40,9 @@
   outSuffixes _ = [".fasta"]
   getSeed _ = Nothing
   setSeed = const
-  parser  = filterRowsArguments
+  parser = filterRowsArguments
   cmdName = "filter-rows"
-  cmdDsc  = ["Filter rows (or sequences) found in input files."]
+  cmdDsc = ["Filter rows (or sequences) found in input files."]
 
 instance FromJSON FilterRowsArguments
 
@@ -54,9 +50,10 @@
 
 -- | Arguments needed for filtering columns of a multi sequence alignment.
 data FilterColsArguments = FilterColsArguments
-  { fcAlphabet :: Alphabet
-  , fcInFile   :: FilePath
-  , fcStandard :: Maybe Double }
+  { fcAlphabet :: Alphabet,
+    fcInFile :: FilePath,
+    fcStandard :: Maybe Double
+  }
   deriving (Eq, Show, Generic)
 
 instance Reproducible FilterColsArguments where
@@ -64,9 +61,9 @@
   outSuffixes _ = [".fasta"]
   getSeed _ = Nothing
   setSeed = const
-  parser  = filterColsArguments
+  parser = filterColsArguments
   cmdName = "filter-columns"
-  cmdDsc  = ["Filter columns of multi sequence alignments."]
+  cmdDsc = ["Filter columns of multi sequence alignments."]
 
 instance FromJSON FilterColsArguments
 
@@ -84,20 +81,26 @@
 
 filterLongerThanOpt :: Parser (Maybe Int)
 filterLongerThanOpt =
-  optional $ option auto $ long "longer-than" <> metavar "LENGTH" <> help
-    "Only keep sequences longer than LENGTH"
+  optional $
+    option auto $
+      long "longer-than" <> metavar "LENGTH"
+        <> help
+          "Only keep sequences longer than LENGTH"
 
 filterShorterThanOpt :: Parser (Maybe Int)
 filterShorterThanOpt =
-  optional $ option auto $ long "shorter-than" <> metavar "LENGTH" <> help
-    "Only keep sequences shorter than LENGTH"
+  optional $
+    option auto $
+      long "shorter-than" <> metavar "LENGTH"
+        <> help
+          "Only keep sequences shorter than LENGTH"
 
 filterStandardChars :: Parser Bool
 filterStandardChars =
-  switch
-    $  long "standard-characters"
-    <> help
-         "Only keep sequences containing at least one standard (i.e., non-IUPAC) character"
+  switch $
+    long "standard-characters"
+      <> help
+        "Only keep sequences containing at least one standard (i.e., non-IUPAC) character"
 
 -- | Command line parser.
 filterColsArguments :: Parser FilterColsArguments
@@ -106,12 +109,12 @@
 
 filterStandardOpt :: Parser (Maybe Double)
 filterStandardOpt =
-  optional
-    $  option auto
-    $  long "standard-chars"
-    <> metavar "DOUBLE"
-    <> help
-         "Keep columns with a proportion standard (non-IUPAC) characters larger than DOUBLE in [0,1]"
+  optional $
+    option auto $
+      long "standard-chars"
+        <> metavar "DOUBLE"
+        <> help
+          "Keep columns with a proportion standard (non-IUPAC) characters larger than DOUBLE in [0,1]"
 
 inFileArg :: Parser FilePath
 inFileArg =
diff --git a/src/SLynx/Options.hs b/src/SLynx/Options.hs
--- a/src/SLynx/Options.hs
+++ b/src/SLynx/Options.hs
@@ -1,41 +1,36 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Options
-Description :  SLynx general options
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sat Sep  7 18:55:03 2019.
-
--}
-
+-- |
+-- Module      :  SLynx.Options
+-- Description :  SLynx general options
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sat Sep  7 18:55:03 2019.
 module SLynx.Options
-  ( Arguments(..)
-  , CommandArguments(..)
-  , parseArguments
+  ( Arguments (..),
+    CommandArguments (..),
+    parseArguments,
   )
 where
 
-import           Options.Applicative
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Tools
-
-import           SLynx.Concatenate.Options
-import           SLynx.Examine.Options
-import           SLynx.Filter.Options
-import           SLynx.Simulate.Options
-import           SLynx.SubSample.Options
-import           SLynx.Translate.Options
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Concatenate.Options
+import SLynx.Examine.Options
+import SLynx.Filter.Options
+import SLynx.Simulate.Options
+import SLynx.SubSample.Options
+import SLynx.Translate.Options
 
 -- | The different SLynx commands and their arguments.
-data CommandArguments =
-  Concatenate ConcatenateArguments
+data CommandArguments
+  = Concatenate ConcatenateArguments
   | Examine ExamineArguments
   | FilterCols FilterColsArguments
   | FilterRows FilterRowsArguments
@@ -46,52 +41,54 @@
 
 instance Reproducible CommandArguments where
   inFiles (Concatenate a) = inFiles a
-  inFiles (Examine     a) = inFiles a
-  inFiles (FilterCols  a) = inFiles a
-  inFiles (FilterRows  a) = inFiles a
-  inFiles (Simulate    a) = inFiles a
-  inFiles (SubSample   a) = inFiles a
-  inFiles (Translate   a) = inFiles a
+  inFiles (Examine a) = inFiles a
+  inFiles (FilterCols a) = inFiles a
+  inFiles (FilterRows a) = inFiles a
+  inFiles (Simulate a) = inFiles a
+  inFiles (SubSample a) = inFiles a
+  inFiles (Translate a) = inFiles a
 
   outSuffixes (Concatenate a) = outSuffixes a
-  outSuffixes (Examine     a) = outSuffixes a
-  outSuffixes (FilterCols  a) = outSuffixes a
-  outSuffixes (FilterRows  a) = outSuffixes a
-  outSuffixes (Simulate    a) = outSuffixes a
-  outSuffixes (SubSample   a) = outSuffixes a
-  outSuffixes (Translate   a) = outSuffixes a
+  outSuffixes (Examine a) = outSuffixes a
+  outSuffixes (FilterCols a) = outSuffixes a
+  outSuffixes (FilterRows a) = outSuffixes a
+  outSuffixes (Simulate a) = outSuffixes a
+  outSuffixes (SubSample a) = outSuffixes a
+  outSuffixes (Translate a) = outSuffixes a
 
   getSeed (Concatenate a) = getSeed a
-  getSeed (Examine     a) = getSeed a
-  getSeed (FilterCols  a) = getSeed a
-  getSeed (FilterRows  a) = getSeed a
-  getSeed (Simulate    a) = getSeed a
-  getSeed (SubSample   a) = getSeed a
-  getSeed (Translate   a) = getSeed a
+  getSeed (Examine a) = getSeed a
+  getSeed (FilterCols a) = getSeed a
+  getSeed (FilterRows a) = getSeed a
+  getSeed (Simulate a) = getSeed a
+  getSeed (SubSample a) = getSeed a
+  getSeed (Translate a) = getSeed a
 
   setSeed (Concatenate a) = Concatenate . setSeed a
-  setSeed (Examine     a) = Examine . setSeed a
-  setSeed (FilterCols  a) = FilterCols . setSeed a
-  setSeed (FilterRows  a) = FilterRows . setSeed a
-  setSeed (Simulate    a) = Simulate . setSeed a
-  setSeed (SubSample   a) = SubSample . setSeed a
-  setSeed (Translate   a) = Translate . setSeed a
+  setSeed (Examine a) = Examine . setSeed a
+  setSeed (FilterCols a) = FilterCols . setSeed a
+  setSeed (FilterRows a) = FilterRows . setSeed a
+  setSeed (Simulate a) = Simulate . setSeed a
+  setSeed (SubSample a) = SubSample . setSeed a
+  setSeed (Translate a) = Translate . setSeed a
 
-  parser  = commandArguments
+  parser = commandArguments
 
   cmdName = "slynx"
 
-  cmdDsc  = ["Analyze, and simulate multi sequence alignments."]
+  cmdDsc = ["Analyze, and simulate multi sequence alignments."]
 
   cmdFtr =
-    ["Available sequence file formats:"]
+    [ "",
+      "Available sequence file formats:"
+    ]
       ++ fs
       ++ ["", "Available alphabets:"]
       ++ as
-   where
-    toListItem = ("  - " ++)
-    fs = map toListItem ["FASTA"]
-    as = map (toListItem . alphabetDescription) (allValues :: [Alphabet])
+    where
+      toListItem = ("  - " ++)
+      fs = map toListItem ["FASTA"]
+      as = map (toListItem . alphabetDescription) (allValues :: [Alphabet])
 
 instance FromJSON CommandArguments
 
@@ -120,11 +117,11 @@
 
 commandArguments :: Parser CommandArguments
 commandArguments =
-  hsubparser
-    $  concatenateCommand
-    <> examineCommand
-    <> filterColumnsCommand
-    <> filterRowsCommand
-    <> simulateCommand
-    <> subSampleCommand
-    <> translateCommand
+  hsubparser $
+    concatenateCommand
+      <> examineCommand
+      <> filterColumnsCommand
+      <> filterRowsCommand
+      <> simulateCommand
+      <> subSampleCommand
+      <> translateCommand
diff --git a/src/SLynx/SLynx.hs b/src/SLynx/SLynx.hs
--- a/src/SLynx/SLynx.hs
+++ b/src/SLynx/SLynx.hs
@@ -1,60 +1,63 @@
-{- |
-Module      :  SLynx.SLynx
-Description :  SLynx module
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Thu Apr 23 16:38:55 2020.
-
--}
-
+-- |
+-- Module      :  SLynx.SLynx
+-- Description :  SLynx module
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Thu Apr 23 16:38:55 2020.
 module SLynx.SLynx
-  ( slynx
-  , rSLynx
+  ( slynx,
+    rSLynx,
   )
 where
 
-import           SLynx.Options
-
-import           SLynx.Concatenate.Concatenate
-import           SLynx.Examine.Examine
-import           SLynx.Filter.Filter
-import           SLynx.Simulate.Simulate
-import           SLynx.SubSample.SubSample
-import           SLynx.Translate.Translate
-
-import           ELynx.Tools
+import ELynx.Tools
+import SLynx.Concatenate.Concatenate
+import SLynx.Examine.Examine
+import SLynx.Filter.Filter
+import SLynx.Options
+import SLynx.Simulate.Simulate
+import SLynx.SubSample.SubSample
+import SLynx.Translate.Translate
 
 -- TODO: Use a class here (e.g., elynx-wrappable) which defines the extractor function.
+
 -- | Run SLynx with given arguments.
 slynx :: Arguments CommandArguments -> IO ()
 slynx c = case local c of
-  Concatenate _ -> eLynxWrapper
-    c
-    (\(Arguments g (Concatenate l)) -> Arguments g l)
-    concatenateCmd
+  Concatenate _ ->
+    eLynxWrapper
+      c
+      (\(Arguments g (Concatenate l)) -> Arguments g l)
+      concatenateCmd
   Examine _ ->
     eLynxWrapper c (\(Arguments g (Examine l)) -> Arguments g l) examineCmd
-  FilterCols _ -> eLynxWrapper
-    c
-    (\(Arguments g (FilterCols l)) -> Arguments g l)
-    filterColsCmd
-  FilterRows _ -> eLynxWrapper
-    c
-    (\(Arguments g (FilterRows l)) -> Arguments g l)
-    filterRowsCmd
+  FilterCols _ ->
+    eLynxWrapper
+      c
+      (\(Arguments g (FilterCols l)) -> Arguments g l)
+      filterColsCmd
+  FilterRows _ ->
+    eLynxWrapper
+      c
+      (\(Arguments g (FilterRows l)) -> Arguments g l)
+      filterRowsCmd
   Simulate _ ->
     eLynxWrapper c (\(Arguments g (Simulate l)) -> Arguments g l) simulateCmd
-  SubSample _ -> eLynxWrapper c
-                              (\(Arguments g (SubSample l)) -> Arguments g l)
-                              subSampleCmd
-  Translate _ -> eLynxWrapper c
-                              (\(Arguments g (Translate l)) -> Arguments g l)
-                              translateCmd
+  SubSample _ ->
+    eLynxWrapper
+      c
+      (\(Arguments g (SubSample l)) -> Arguments g l)
+      subSampleCmd
+  Translate _ ->
+    eLynxWrapper
+      c
+      (\(Arguments g (Translate l)) -> Arguments g l)
+      translateCmd
 
 -- | Run SLynx, parse arguments from command line.
 rSLynx :: IO ()
diff --git a/src/SLynx/Simulate/Options.hs b/src/SLynx/Simulate/Options.hs
--- a/src/SLynx/Simulate/Options.hs
+++ b/src/SLynx/Simulate/Options.hs
@@ -1,85 +1,80 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Simulate.Options
-Description :  ELynxSim argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
-Available options:
-  -h,--help                Show this help text
-  -v,--version             Show version
-  -t,--tree-file NAME      Specify tree file NAME
-  -s,--substitution-model MODEL
-                           Set the phylogenetic substitution model; available
-                           models are shown below
-  -m,--mixture-model MODEL Set the phylogenetic mixture model; available models
-                           are shown below
-  -l,--length NUMBER       Set alignment length to NUMBER
-  -e,--edm-file NAME       empirical distribution model file NAME in Phylobayes
-                           format
-  -w,--mixture-model-weights [DOUBLE,DOUBLE,...]
-                           weights of mixture model components
-  -g,--gamma-rate-heterogeneity (NCAT, SHAPE)
-                           number of gamma rate categories and shape parameter
-  -e,--seed [INT]            Set seed for the random number generator; list of 32
-                           bit integers with up to 256 elements (default: [0])
-  -q,--quiet               Be quiet
-  -o,--output-file NAME    Specify output file NAME
-
-
--}
-
-
+-- |
+-- Module      :  SLynx.Simulate.Options
+-- Description :  ELynxSim argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
+--
+-- Available options:
+--   -h,--help                Show this help text
+--   -v,--version             Show version
+--   -t,--tree-file NAME      Specify tree file NAME
+--   -s,--substitution-model MODEL
+--                            Set the phylogenetic substitution model; available
+--                            models are shown below
+--   -m,--mixture-model MODEL Set the phylogenetic mixture model; available models
+--                            are shown below
+--   -l,--length NUMBER       Set alignment length to NUMBER
+--   -e,--edm-file NAME       empirical distribution model file NAME in Phylobayes
+--                            format
+--   -w,--mixture-model-weights [DOUBLE,DOUBLE,...]
+--                            weights of mixture model components
+--   -g,--gamma-rate-heterogeneity (NCAT, SHAPE)
+--                            number of gamma rate categories and shape parameter
+--   -e,--seed [INT]            Set seed for the random number generator; list of 32
+--                            bit integers with up to 256 elements (default: [0])
+--   -q,--quiet               Be quiet
+--   -o,--output-file NAME    Specify output file NAME
 module SLynx.Simulate.Options
-  ( GammaRateHeterogeneityParams
-  , SimulateArguments(..)
-  , simulateArguments
-  , simulateFooter
+  ( GammaRateHeterogeneityParams,
+    SimulateArguments (..),
+    simulateArguments,
+    simulateFooter,
   )
 where
 
-import           Data.Maybe                     ( maybeToList
-                                                , fromMaybe
-                                                )
-import           Options.Applicative
-
-import           ELynx.Tools
+import Data.Maybe
+  ( fromMaybe,
+    maybeToList,
+  )
+import ELynx.Tools
+import Options.Applicative
 
 -- | Number of gamma rate categories and alpha parameter.
 type GammaRateHeterogeneityParams = (Int, Double)
 
 -- | Arguments needed to simulate sequences.
 data SimulateArguments = SimulateArguments
-  { argsTreeFile                :: FilePath
-  , argsSubstitutionModelString :: Maybe String
-  , argsMixtureModelString      :: Maybe String
-  , argsEDMFile                 :: Maybe FilePath
-  , argsSiteprofilesFiles       :: Maybe [FilePath]
-  , argsMixtureWeights          :: Maybe [Double]
-  , argsGammaParams             :: Maybe GammaRateHeterogeneityParams
-  , argsLength                  :: Int
-  , argsSeed                    :: Seed
+  { argsTreeFile :: FilePath,
+    argsSubstitutionModelString :: Maybe String,
+    argsMixtureModelString :: Maybe String,
+    argsEDMFile :: Maybe FilePath,
+    argsSiteprofilesFiles :: Maybe [FilePath],
+    argsMixtureWeights :: Maybe [Double],
+    argsGammaParams :: Maybe GammaRateHeterogeneityParams,
+    argsLength :: Int,
+    argsSeed :: Seed
   }
   deriving (Eq, Show, Generic)
 
 instance Reproducible SimulateArguments where
   inFiles a =
-    argsTreeFile a
-      : (maybeToList (argsEDMFile a) ++ fromMaybe [] (argsSiteprofilesFiles a))
+    argsTreeFile a :
+    (maybeToList (argsEDMFile a) ++ fromMaybe [] (argsSiteprofilesFiles a))
   outSuffixes _ = [".model.gz", ".fasta"]
   getSeed = Just . argsSeed
-  setSeed a s = a { argsSeed = Fixed s }
-  parser  = simulateArguments
+  setSeed a s = a {argsSeed = Fixed s}
+  parser = simulateArguments
   cmdName = "simulate"
-  cmdDsc  = ["Simulate multi sequence alignments."]
-  cmdFtr  = simulateFooter
+  cmdDsc = ["Simulate multi sequence alignments."]
+  cmdFtr = simulateFooter
 
 instance FromJSON SimulateArguments
 
@@ -101,112 +96,124 @@
 
 treeFileOpt :: Parser FilePath
 treeFileOpt =
-  strOption $ long "tree-file" <> short 't' <> metavar "Name" <> help
-    "Read tree from Newick file NAME"
+  strOption $
+    long "tree-file" <> short 't' <> metavar "Name"
+      <> help
+        "Read tree from Newick file NAME"
 
 phyloSubstitutionModelOpt :: Parser (Maybe String)
 phyloSubstitutionModelOpt =
-  optional
-    $  strOption
-    $  long "substitution-model"
-    <> short 's'
-    <> metavar "MODEL"
-    <> help
-         "Set the phylogenetic substitution model; available models are shown below (mutually exclusive with -m option)"
+  optional $
+    strOption $
+      long "substitution-model"
+        <> short 's'
+        <> metavar "MODEL"
+        <> help
+          "Set the phylogenetic substitution model; available models are shown below (mutually exclusive with -m option)"
 
 phyloMixtureModelOpt :: Parser (Maybe String)
-phyloMixtureModelOpt = optional $ strOption
-  (  long "mixture-model"
-  <> short 'm'
-  <> metavar "MODEL"
-  <> help
-       "Set the phylogenetic mixture model; available models are shown below (mutually exclusive with -s option)"
-  )
+phyloMixtureModelOpt =
+  optional $
+    strOption
+      ( long "mixture-model"
+          <> short 'm'
+          <> metavar "MODEL"
+          <> help
+            "Set the phylogenetic mixture model; available models are shown below (mutually exclusive with -s option)"
+      )
 
 maybeEDMFileOpt :: Parser (Maybe FilePath)
-maybeEDMFileOpt = optional $ strOption
-  (long "edm-file" <> short 'e' <> metavar "NAME" <> help
-    "Empirical distribution model file NAME in Phylobayes format"
-  )
-
--- fn :: Parsec Void String FilePath
--- fn = space *> takeWhile1P () <* space
-
--- fns :: Parsec Void String [FilePath]
--- fns = do
---   many string
+maybeEDMFileOpt =
+  optional $
+    strOption
+      ( long "edm-file" <> short 'e' <> metavar "NAME"
+          <> help
+            "Empirical distribution model file NAME in Phylobayes format"
+      )
 
 maybeSiteprofilesFilesOpt :: Parser (Maybe [FilePath])
-maybeSiteprofilesFilesOpt = optional $ words <$> strOption
-  (long "siteprofile-files" <> short 'p' <> metavar "NAMES" <> help
-    "File names of site profiles in Phylobayes format"
-  )
+maybeSiteprofilesFilesOpt =
+  optional $
+    words
+      <$> strOption
+        ( long "siteprofile-files" <> short 'p' <> metavar "NAMES"
+            <> help
+              "File names of site profiles in Phylobayes format"
+        )
 
 maybeMixtureWeights :: Parser (Maybe [Double])
-maybeMixtureWeights = optional $ option
-  auto
-  (  long "mixture-model-weights"
-  <> short 'w'
-  <> metavar "\"[DOUBLE,DOUBLE,...]\""
-  <> help "Weights of mixture model components"
-  )
+maybeMixtureWeights =
+  optional $
+    option
+      auto
+      ( long "mixture-model-weights"
+          <> short 'w'
+          <> metavar "\"[DOUBLE,DOUBLE,...]\""
+          <> help "Weights of mixture model components"
+      )
 
 maybeGammaParams :: Parser (Maybe GammaRateHeterogeneityParams)
-maybeGammaParams = optional $ option
-  auto
-  (  long "gamma-rate-heterogeneity"
-  <> short 'g'
-  <> metavar "\"(NCAT,SHAPE)\""
-  <> help "Number of gamma rate categories and shape parameter"
-  )
+maybeGammaParams =
+  optional $
+    option
+      auto
+      ( long "gamma-rate-heterogeneity"
+          <> short 'g'
+          <> metavar "\"(NCAT,SHAPE)\""
+          <> help "Number of gamma rate categories and shape parameter"
+      )
 
 lengthOpt :: Parser Int
-lengthOpt = option
-  auto
-  (long "length" <> short 'l' <> metavar "NUMBER" <> help
-    "Set alignment length to NUMBER"
-  )
+lengthOpt =
+  option
+    auto
+    ( long "length" <> short 'l' <> metavar "NUMBER"
+        <> help
+          "Set alignment length to NUMBER"
+    )
 
 -- | The model specification is somewhat complicated, so we need to provide
 -- additional help.
 simulateFooter :: [String]
 simulateFooter = sms ++ mms
- where
-  sms =
-    [ "Substitution models:"
-    , "-s \"MODEL[PARAMETER,PARAMETER,...]{STATIONARY_DISTRIBUTION}\""
-    , "   Supported DNA models: JC, F81, HKY, GTR4."
-    , "     For example,"
-    , "       -s HKY[KAPPA]{DOUBLE,DOUBLE,DOUBLE,DOUBLE}"
-    , "       -s GTR4[e_AC,e_AG,e_AT,e_CG,e_CT,e_GT]{DOUBLE,DOUBLE,DOUBLE,DOUBLE}"
-    , "          where the 'e_XY' are the exchangeabilities from nucleotide X to Y."
-    , "   Supported Protein models: Poisson, Poisson-Custom, LG, LG-Custom, WAG, WAG-Custom, GTR20."
-    , "     MODEL-Custom means that only the exchangeabilities of MODEL are used,"
-    , "     and a custom stationary distribution is provided."
-    , "     For example,"
-    , "       -s LG"
-    , "       -s LG-Custom{...}"
-    , "       -s GTR20[e_AR,e_AN,...]{...}"
-    , "          the 'e_XY' are the exchangeabilities from amino acid X to Y (alphabetical order)."
-    , "   Notes: The F81 model for DNA is equivalent to the Poisson-Custom for proteins."
-    , "          The GTR4 model for DNA is equivalent to the GTR20 for proteins."
-    ]
-  mms =
-    [ ""
-    , "Mixture models:"
-    , "-m \"MIXTURE(SUBSTITUTION_MODEL_1,SUBSTITUTION_MODEL_2[PARAMETERS]{STATIONARY_DISTRIBUTION},...)\""
-    , "   For example,"
-    , "     -m \"MIXTURE(JC,HKY[6.0]{0.3,0.2,0.2,0.3})\""
-    , "Mixture weights have to be provided with the -w option."
-    , ""
-    , "Special mixture models:"
-    , "-m CXX"
-    , "   where XX is 10, 20, 30, 40, 50, or 60; CXX models, Quang et al., 2008."
-    , "-m \"EDM(EXCHANGEABILITIES)\""
-    , "   Arbitrary empirical distribution mixture (EDM) models."
-    , "   Stationary distributions have to be provided with the -e option."
-    , "   For example,"
-    , "     LG exchangeabilities with stationary distributions given in FILE."
-    , "     -m \"EDM(LG-Custom)\" -e FILE"
-    , "For special mixture models, mixture weights are optional."
-    ]
+  where
+    sms =
+      [ "Substitution models:",
+        "-s \"MODEL[PARAMETER,PARAMETER,...]{STATIONARY_DISTRIBUTION}\"",
+        "   Supported DNA models: JC, F81, HKY, GTR4.",
+        "     For example,",
+        "       -s HKY[KAPPA]{DOUBLE,DOUBLE,DOUBLE,DOUBLE}",
+        "       -s GTR4[e_AC,e_AG,e_AT,e_CG,e_CT,e_GT]{DOUBLE,DOUBLE,DOUBLE,DOUBLE}",
+        "          where the 'e_XY' are the exchangeabilities from nucleotide X to Y.",
+        "   Supported Protein models: Poisson, Poisson-Custom, LG, LG-Custom, WAG, WAG-Custom, GTR20.",
+        "     MODEL-Custom means that only the exchangeabilities of MODEL are used,",
+        "     and a custom stationary distribution is provided.",
+        "     For example,",
+        "       -s LG",
+        "       -s LG-Custom{...}",
+        "       -s GTR20[e_AR,e_AN,...]{...}",
+        "          the 'e_XY' are the exchangeabilities from amino acid X to Y (alphabetical order).",
+        "   Notes: The F81 model for DNA is equivalent to the Poisson-Custom for proteins.",
+        "          The GTR4 model for DNA is equivalent to the GTR20 for proteins."
+      ]
+    mms =
+      [ "",
+        "Mixture models:",
+        "-m \"MIXTURE(SUBSTITUTION_MODEL_1,SUBSTITUTION_MODEL_2[PARAMETERS]{STATIONARY_DISTRIBUTION},...)\"",
+        "   For example,",
+        "     -m \"MIXTURE(JC,HKY[6.0]{0.3,0.2,0.2,0.3})\"",
+        "Mixture weights have to be provided with the -w option.",
+        "",
+        "Special mixture models:",
+        "-m CXX",
+        "   where XX is 10, 20, 30, 40, 50, or 60; CXX models, Quang et al., 2008.",
+        "-m \"EDM(EXCHANGEABILITIES)\"",
+        "   Arbitrary empirical distribution mixture (EDM) models.",
+        "   Stationary distributions have to be provided with the -e or -p option.",
+        "   For example,",
+        "     LG exchangeabilities with stationary distributions given in FILE.",
+        "     -m \"EDM(LG-Custom)\" -e FILE",
+        "     LG exchangeabilities with site profiles (Phylobayes) given in FILES.",
+        "     -m \"EDM(LG-Custom)\" -p FILES",
+        "For special mixture models, mixture weights are optional."
+      ]
diff --git a/src/SLynx/Simulate/PhyloModel.hs b/src/SLynx/Simulate/PhyloModel.hs
--- a/src/SLynx/Simulate/PhyloModel.hs
+++ b/src/SLynx/Simulate/PhyloModel.hs
@@ -1,51 +1,46 @@
-{- |
-Module      :  SLynx.Simulate.PhyloModel
-Description :  Parse and interpret the model string
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Feb  1 13:32:16 2019.
-
--}
-
+-- |
+-- Module      :  SLynx.Simulate.PhyloModel
+-- Description :  Parse and interpret the model string
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Feb  1 13:32:16 2019.
 module SLynx.Simulate.PhyloModel
-  ( getPhyloModel
+  ( getPhyloModel,
   )
 where
 
-import           Control.Monad                  ( when )
-import qualified Data.ByteString.Lazy.Char8    as L
-import           Data.Either                    ( rights )
-import           Data.List.NonEmpty             ( fromList )
-import           Data.Maybe
-import           Data.Scientific         hiding ( scientific )
-import           Data.Void
-import           Data.Word                      ( Word8 )
-import           Numeric.LinearAlgebra          ( norm_1
-                                                , size
-                                                , vector
-                                                )
-import           Text.Megaparsec
-import           Text.Megaparsec.Byte
-import           Text.Megaparsec.Byte.Lexer
-
-import           ELynx.Data.MarkovProcess.AminoAcid
-import           ELynx.Data.MarkovProcess.CXXModels
-import qualified ELynx.Data.MarkovProcess.MixtureModel
-                                               as M
-import           ELynx.Data.MarkovProcess.Nucleotide
-import qualified ELynx.Data.MarkovProcess.PhyloModel
-                                               as P
-import           ELynx.Data.MarkovProcess.RateMatrix
-import qualified ELynx.Data.MarkovProcess.SubstitutionModel
-                                               as S
-import           ELynx.Import.MarkovProcess.EDMModelPhylobayes
-                                                ( EDMComponent )
-import           ELynx.Tools
+import Control.Monad (when)
+import qualified Data.ByteString.Lazy.Char8 as L
+import Data.Either (rights)
+import Data.List.NonEmpty (fromList)
+import Data.Maybe
+import Data.Scientific hiding (scientific)
+import Data.Void
+import Data.Word (Word8)
+import ELynx.Data.MarkovProcess.AminoAcid
+import ELynx.Data.MarkovProcess.CXXModels
+import qualified ELynx.Data.MarkovProcess.MixtureModel as M
+import ELynx.Data.MarkovProcess.Nucleotide
+import qualified ELynx.Data.MarkovProcess.PhyloModel as P
+import ELynx.Data.MarkovProcess.RateMatrix
+import qualified ELynx.Data.MarkovProcess.SubstitutionModel as S
+import ELynx.Import.MarkovProcess.EDMModelPhylobayes
+  ( EDMComponent,
+  )
+import ELynx.Tools
+import Numeric.LinearAlgebra
+  ( norm_1,
+    size,
+    vector,
+  )
+import Text.Megaparsec
+import Text.Megaparsec.Byte
+import Text.Megaparsec.Byte.Lexer
 
 type Parser = Parsec Void L.ByteString
 
@@ -85,48 +80,56 @@
 separator = c2w ','
 
 name :: Parser String
-name = L.unpack <$> takeWhile1P
-  (Just "Model name")
-  (`notElem` [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator]
-  )
+name =
+  L.unpack
+    <$> takeWhile1P
+      (Just "Model name")
+      ( `notElem` [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator]
+      )
 
 params :: Parser [Double]
-params = map toRealFloat <$> between (char paramsStart)
-                                     (char paramsEnd)
-                                     (sepBy1 scientific (char separator))
+params =
+  map toRealFloat
+    <$> between
+      (char paramsStart)
+      (char paramsEnd)
+      (sepBy1 scientific (char separator))
 
 stationaryDistribution :: Parser StationaryDistribution
 stationaryDistribution = do
-  f <- vector . map toRealFloat <$> between
-    (char sdStart)
-    (char sdEnd)
-    (sepBy1 scientific (char separator))
+  f <-
+    vector . map toRealFloat
+      <$> between
+        (char sdStart)
+        (char sdEnd)
+        (sepBy1 scientific (char separator))
   if nearlyEq (norm_1 f) 1.0
     then return f
     else
-      error
-      $  "Sum of stationary distribution is "
-      ++ show (norm_1 f)
-      ++ " but should be 1.0."
+      error $
+        "Sum of stationary distribution is "
+          ++ show (norm_1 f)
+          ++ " but should be 1.0."
 
 assertLength :: StationaryDistribution -> Int -> a -> a
-assertLength d n r = if size d /= n
-  then
-    error
-    $  "Length of stationary distribution is "
-    ++ show (size d)
-    ++ " but should be "
-    ++ show n
-    ++ "."
-  else r
+assertLength d n r =
+  if size d /= n
+    then
+      error $
+        "Length of stationary distribution is "
+          ++ show (size d)
+          ++ " but should be "
+          ++ show n
+          ++ "."
+    else r
 
 -- This is the main function that connects the model string, the parameters and
 -- the stationary distribution. It should check that the model is valid.
-assembleSubstitutionModel
-  :: String
-  -> Maybe S.Params
-  -> Maybe StationaryDistribution
-  -> Either String S.SubstitutionModel
+assembleSubstitutionModel ::
+  String ->
+  Maybe S.Params ->
+  Maybe StationaryDistribution ->
+  Either String S.SubstitutionModel
 -- DNA models.
 assembleSubstitutionModel "JC" Nothing Nothing = Right jc
 assembleSubstitutionModel "F81" Nothing (Just d) =
@@ -148,41 +151,44 @@
 assembleSubstitutionModel "GTR20" (Just es) (Just d) =
   Right $ assertLength d nAA $ gtr20 es d
 -- Ohterwisse, we cannot assemble the model.
-assembleSubstitutionModel n mps mf = Left $ unlines
-  [ "Cannot assemble substitution model."
-  , "Name: " ++ show n
-  , "Parameters: " ++ show mps
-  , "Stationary distribution: " ++ show mf
-  ]
+assembleSubstitutionModel n mps mf =
+  Left $
+    unlines
+      [ "Cannot assemble substitution model.",
+        "Name: " ++ show n,
+        "Parameters: " ++ show mps,
+        "Stationary distribution: " ++ show mf
+      ]
 
 parseSubstitutionModel :: Parser S.SubstitutionModel
 parseSubstitutionModel = do
-  n   <- name
+  n <- name
   mps <- optional params
-  mf  <- optional stationaryDistribution
+  mf <- optional stationaryDistribution
   let esm = assembleSubstitutionModel n mps mf
   case esm of
-    Left  err -> fail err
-    Right sm  -> return sm
+    Left err -> fail err
+    Right sm -> return sm
 
 edmModel :: [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel
 edmModel cs mws = do
-  _   <- chunk (bs "EDM")
-  _   <- char mmStart
-  n   <- name
+  _ <- chunk (bs "EDM")
+  _ <- char mmStart
+  n <- name
   mps <- optional params
-  _   <- char mmEnd
+  _ <- char mmEnd
   when (null cs) $ error "edmModel: no EDM components given."
-  let sms     = map (\c -> assembleSubstitutionModel n mps (Just $ snd c)) cs
+  let sms = map (\c -> assembleSubstitutionModel n mps (Just $ snd c)) cs
       edmName = "EDM" ++ show (length cs)
-      ws      = fromMaybe (map fst cs) mws
-      errs    = [ e | (Left e) <- sms ]
-  when (length sms /= length ws)
-    $ error "edmModel: number of substitution models and weights differs."
+      ws = fromMaybe (map fst cs) mws
+      errs = [e | (Left e) <- sms]
+  when (length sms /= length ws) $
+    error "edmModel: number of substitution models and weights differs."
   if not $ null errs
     then fail $ head errs
-    else return
-      $ M.fromSubstitutionModels edmName (fromList ws) (fromList $ rights sms)
+    else
+      return $
+        M.fromSubstitutionModels edmName (fromList ws) (fromList $ rights sms)
 
 cxxModel :: Maybe [M.Weight] -> Parser M.MixtureModel
 cxxModel mws = do
@@ -192,15 +198,15 @@
 
 standardMixtureModel :: [M.Weight] -> Parser M.MixtureModel
 standardMixtureModel ws = do
-  _   <- chunk (bs "MIXTURE")
-  _   <- char mmStart
+  _ <- chunk (bs "MIXTURE")
+  _ <- char mmStart
   sms <- parseSubstitutionModel `sepBy1` char separator
-  _   <- char mmEnd
+  _ <- char mmEnd
   -- XXX: The use of `Data.List.NonEmpty.fromList` leads to uninformative error messages.
   return $ M.fromSubstitutionModels "MIXTURE" (fromList ws) (fromList sms)
 
-mixtureModel
-  :: Maybe [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel
+mixtureModel ::
+  Maybe [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel
 mixtureModel Nothing Nothing =
   try (cxxModel Nothing) <|> fail "No weights provided."
 mixtureModel Nothing mws@(Just ws) =
@@ -214,25 +220,31 @@
 -- @
 -- getPhyloModel maybeSubstitutionModelString maybeMixtureModelString maybeEDMComponents
 -- @
-getPhyloModel
-  :: Maybe String
-  -> Maybe String
-  -> Maybe [M.Weight]
-  -> Maybe [EDMComponent]
-  -> Either String P.PhyloModel
+getPhyloModel ::
+  Maybe String ->
+  Maybe String ->
+  Maybe [M.Weight] ->
+  Maybe [EDMComponent] ->
+  Either String P.PhyloModel
 getPhyloModel Nothing Nothing _ _ = Left "No model was given. See help."
 getPhyloModel (Just _) (Just _) _ _ =
   Left "Both, substitution and mixture model string given; use only one."
 getPhyloModel (Just s) Nothing Nothing Nothing =
-  Right $ P.SubstitutionModel $ parseStringWith "Substitution model string"
-                                                parseSubstitutionModel
-                                                s
+  Right $
+    P.SubstitutionModel $
+      parseStringWith
+        "Substitution model string"
+        parseSubstitutionModel
+        s
 getPhyloModel (Just _) Nothing (Just _) _ =
   Left "Weights given; but cannot be used with substitution model."
 getPhyloModel (Just _) Nothing _ (Just _) =
   Left
     "Empirical distribution mixture model components given; but cannot be used with substitution model."
 getPhyloModel Nothing (Just m) mws mcs =
-  Right $ P.MixtureModel $ parseStringWith "Mixture model string"
-                                           (mixtureModel mcs mws)
-                                           m
+  Right $
+    P.MixtureModel $
+      parseStringWith
+        "Mixture model string"
+        (mixtureModel mcs mws)
+        m
diff --git a/src/SLynx/Simulate/Simulate.hs b/src/SLynx/Simulate/Simulate.hs
--- a/src/SLynx/Simulate/Simulate.hs
+++ b/src/SLynx/Simulate/Simulate.hs
@@ -1,126 +1,121 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  SLynx.Simulate.Simulate
-Description :  Simulate multiple sequence alignments
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Mon Jan 28 14:12:52 2019.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  SLynx.Simulate.Simulate
+-- Description :  Simulate multiple sequence alignments
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Mon Jan 28 14:12:52 2019.
 module SLynx.Simulate.Simulate
-  ( simulateCmd
+  ( simulateCmd,
   )
 where
 
-import           Control.Applicative            ( (<|>) )
-import           Control.Concurrent
-import           Control.Concurrent.Async
-import           Control.Monad                  ( unless
-                                                , when
-                                                )
-import           Control.Monad.IO.Class
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Class
-import           Control.Monad.Trans.Reader     ( ask )
-import qualified Data.ByteString.Lazy          as L
-import qualified Data.ByteString.Lazy.Char8    as LC
-import           Data.List.NonEmpty             ( toList )
-import           Data.Maybe
-import qualified Data.Set                      as Set
-import qualified Data.Text                     as T
-import qualified Data.Text.Lazy                as LT
-import qualified Data.Text.Lazy.Encoding       as LT
-import           Data.Tree
-import qualified Data.Vector.Unboxed           as V
-import           Numeric.LinearAlgebra   hiding ( (<>)
-                                                , toList
-                                                )
-import           System.Random.MWC
-
-import           SLynx.Simulate.Options
-import           SLynx.Simulate.PhyloModel
-
-import           ELynx.Data.Alphabet.Alphabet  as A
-import           ELynx.Data.MarkovProcess.GammaRateHeterogeneity
-import qualified ELynx.Data.MarkovProcess.MixtureModel
-                                               as M
-import qualified ELynx.Data.MarkovProcess.PhyloModel
-                                               as P
-import qualified ELynx.Data.MarkovProcess.SubstitutionModel
-                                               as SM
+import Control.Applicative ((<|>))
+import Control.Concurrent
+import Control.Concurrent.Async
+import Control.Monad
+  ( unless,
+    when,
+  )
+import Control.Monad.IO.Class
+import Control.Monad.Logger
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy.Char8 as LC
+import Data.List.NonEmpty (toList)
+import Data.Maybe
+import qualified Data.Set as Set
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.Encoding as LT
+import qualified Data.Vector.Unboxed as V
+import ELynx.Data.Alphabet.Alphabet as A
+import ELynx.Data.MarkovProcess.GammaRateHeterogeneity
+import qualified ELynx.Data.MarkovProcess.MixtureModel as M
+import qualified ELynx.Data.MarkovProcess.PhyloModel as P
+import qualified ELynx.Data.MarkovProcess.SubstitutionModel as SM
 import qualified ELynx.Data.Sequence.Alignment as A
-import qualified ELynx.Data.Sequence.Sequence  as Seq
-                                         hiding ( name )
-import           ELynx.Data.Tree
-import           ELynx.Export.Sequence.Fasta
-import           ELynx.Import.MarkovProcess.EDMModelPhylobayes
-                                         hiding ( Parser )
-import           ELynx.Import.MarkovProcess.SiteprofilesPhylobayes
-import           ELynx.Import.Tree.Newick
-                                         hiding ( name )
-import           ELynx.Simulate.MarkovProcessAlongTree
-
-import           ELynx.Tools
+import qualified ELynx.Data.Sequence.Sequence as Seq hiding
+  ( name,
+  )
+import ELynx.Data.Tree
+import ELynx.Export.Sequence.Fasta
+import ELynx.Import.MarkovProcess.EDMModelPhylobayes hiding
+  ( Parser,
+  )
+import ELynx.Import.MarkovProcess.SiteprofilesPhylobayes
+import ELynx.Import.Tree.Newick
+import ELynx.Simulate.MarkovProcessAlongTree
+import ELynx.Tools
+import Numeric.LinearAlgebra hiding
+  ( toList,
+    (<>),
+  )
+import SLynx.Simulate.Options
+import SLynx.Simulate.PhyloModel
+import System.Random.MWC
 
 -- Simulate a 'Alignment' for a given phylogenetic model,
 -- phylogenetic tree, and alignment length.
-simulateAlignment
-  :: (Measurable a, Named a)
-  => P.PhyloModel
-  -> Tree a
-  -> Int
-  -> GenIO
-  -> IO A.Alignment
-simulateAlignment pm t n g = do
-  c  <- getNumCapabilities
+simulateAlignment ::
+  (Measurable e, Named a) =>
+  P.PhyloModel ->
+  Tree e a ->
+  Int ->
+  GenIO ->
+  IO A.Alignment
+simulateAlignment pm t' n g = do
+  let t = getLen <$> toTreeBranchLabels t'
+  c <- getNumCapabilities
   gs <- splitGen c g
   let chunks = getChunks c n
   leafStatesS <- case pm of
-    -- XXX @performace: This parallelization is not very intelligent, because
-    -- the matrices exponentiation is done in all threads. So ten threads will
+    -- TODO @performace: This parallelization is not very intelligent, because
+    -- the matrix exponentiation is done in all threads. So ten threads will
     -- exponentiate the same matrix ten times.
-    P.SubstitutionModel sm -> mapConcurrently
-      (\(num, gen) -> simulateAndFlatten num d e t gen)
-      (zip chunks gs)
-     where
-      d = SM.stationaryDistribution sm
-      e = SM.exchangeabilityMatrix sm
+    P.SubstitutionModel sm ->
+      mapConcurrently
+        (\(num, gen) -> simulateAndFlatten num d e t gen)
+        (zip chunks gs)
+      where
+        d = SM.stationaryDistribution sm
+        e = SM.exchangeabilityMatrix sm
     -- P.MixtureModel mm      -> mapConcurrently
     --   (\(num, gen) -> simulateAndFlattenNSitesAlongTreeMixtureModel num ws ds es t gen) (zip chunks gs)
     P.MixtureModel mm -> simulateAndFlattenMixtureModelPar n ws ds es t g
-     where
-      ws = vector . toList $ M.getWeights mm
-      ds = map SM.stationaryDistribution $ toList $ M.getSubstitutionModels mm
-      es = map SM.exchangeabilityMatrix $ toList $ M.getSubstitutionModels mm
+      where
+        ws = vector . toList $ M.getWeights mm
+        ds = map SM.stationaryDistribution $ toList $ M.getSubstitutionModels mm
+        es = map SM.exchangeabilityMatrix $ toList $ M.getSubstitutionModels mm
   -- XXX @performace. The horizontal concatenation might be slow. If so,
   -- 'concatenateSeqs' or 'concatenateAlignments' can be used, which directly
   -- appends vectors.
   let leafStates = horizontalConcat leafStatesS
-      leafNames  = map getName $ leaves t
-      code       = P.getAlphabet pm
+      leafNames = map getName $ leaves t'
+      code = P.getAlphabet pm
       -- XXX: Probably use type safe stuff here?
-      alph       = A.all $ alphabetSpec code
+      alph = A.all $ alphabetSpec code
       sequences =
         [ Seq.Sequence sName "" code (V.fromList $ map (`Set.elemAt` alph) ss)
-        | (sName, ss) <- zip leafNames leafStates
+          | (sName, ss) <- zip leafNames leafStates
         ]
   return $ either error id $ A.fromSequences sequences
 
 -- Summarize EDM components; line to be printed to screen or log.
 summarizeEDMComponents :: [EDMComponent] -> L.ByteString
 summarizeEDMComponents cs =
-  LC.pack
-    $  "Empiricial distribution mixture model with "
-    ++ show (length cs)
-    ++ " components."
+  LC.pack $
+    "Empiricial distribution mixture model with "
+      ++ show (length cs)
+      ++ " components."
 
 -- XXX. Maybe provide human readable model file. But then, why is this
 -- necessary. A human readable summary is reported anyways, and for Protein
@@ -140,81 +135,82 @@
 simulateCmd = do
   l <- local <$> ask
   let treeFile = argsTreeFile l
-
   $(logInfo) ""
   $(logInfo) $ T.pack $ "Read tree from file '" ++ treeFile ++ "'."
   tree <- liftIO $ parseFileWith (newick Standard) treeFile
-  $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ summarize tree
-
-  let edmFile       = argsEDMFile l
+  let t' = either error id $ phyloToLengthTree tree
+  $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ summarizeBranchLengths t'
+  let edmFile = argsEDMFile l
   let sProfileFiles = argsSiteprofilesFiles l
   $(logInfo) ""
   $(logDebug) "Read EDM file or siteprofile files."
-  when (isJust edmFile && isJust sProfileFiles)
-    $ error "Got both: --edm-file and --siteprofile-files."
+  when (isJust edmFile && isJust sProfileFiles) $
+    error "Got both: --edm-file and --siteprofile-files."
   edmCs <- case edmFile of
-    Nothing   -> return Nothing
+    Nothing -> return Nothing
     Just edmF -> do
       $(logInfo) "Read EDM file."
       liftIO $ Just <$> parseFileWith phylobayes edmF
-  maybe (return ())
-        ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents)
-        edmCs
+  maybe
+    (return ())
+    ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents)
+    edmCs
   sProfiles <- case sProfileFiles of
-    Nothing  -> return Nothing
+    Nothing -> return Nothing
     Just fns -> do
-      $(logInfo)
-        $  T.pack
-        $  "Read siteprofiles from "
-        ++ show (length fns)
-        ++ " file(s)."
+      $(logInfo) $
+        T.pack $
+          "Read siteprofiles from "
+            ++ show (length fns)
+            ++ " file(s)."
       $(logDebug) $ T.pack $ "The file names are:" ++ show fns
       xs <- liftIO $ mapM (parseFileWith siteprofiles) fns
       return $ Just $ concat xs
-  maybe (return ())
-        ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents)
-        sProfiles
+  maybe
+    (return ())
+    ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents)
+    sProfiles
   let edmCsOrSiteprofiles = edmCs <|> sProfiles
-
   $(logInfo) "Read model string."
-  let ms                = argsSubstitutionModelString l
-      mm                = argsMixtureModelString l
-      mws               = argsMixtureWeights l
+  let ms = argsSubstitutionModelString l
+      mm = argsMixtureModelString l
+      mws = argsMixtureWeights l
       eitherPhyloModel' = getPhyloModel ms mm mws edmCsOrSiteprofiles
   phyloModel' <- case eitherPhyloModel' of
-    Left  err -> lift $ error err
-    Right pm  -> return pm
-
+    Left err -> lift $ error err
+    Right pm -> return pm
   let maybeGammaParams = argsGammaParams l
   phyloModel <- case maybeGammaParams of
     Nothing -> do
-      $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ LC.unlines $ P.summarize
-        phyloModel'
+      $(logInfo) $
+        LT.toStrict $
+          LT.decodeUtf8 $
+            LC.unlines $
+              P.summarize
+                phyloModel'
       return phyloModel'
     Just (n, alpha) -> do
-      $(logInfo)
-        $ LT.toStrict
-        $ LT.decodeUtf8
-        $ LC.intercalate "\n"
-        $ P.summarize phyloModel'
+      $(logInfo) $
+        LT.toStrict $
+          LT.decodeUtf8 $
+            LC.intercalate "\n" $
+              P.summarize phyloModel'
       $(logInfo) ""
-      $(logInfo)
-        $ LT.toStrict
-        $ LT.decodeUtf8
-        $ LC.intercalate "\n"
-        $ summarizeGammaRateHeterogeneity n alpha
+      $(logInfo) $
+        LT.toStrict $
+          LT.decodeUtf8 $
+            LC.intercalate "\n" $
+              summarizeGammaRateHeterogeneity n alpha
       return $ expand n alpha phyloModel'
-
   -- -- XXX: Do not report possibly huge empirical distribution mixture models
   -- -- for now, because it takes too long and uses too much disk space :).
   unless
     (isJust sProfiles)
-    (do
-      $(logInfo) ""
-      reportModel phyloModel
-      $(logInfo) ""
+    ( do
+        $(logInfo) ""
+        reportModel phyloModel
+        $(logInfo) ""
     )
-
   $(logInfo) "Simulate alignment."
   let alignmentLength = argsLength l
   $(logInfo) $ T.pack $ "Length: " <> show alignmentLength <> "."
@@ -222,7 +218,7 @@
     Random ->
       error "simulateCmd: seed not available; please contact maintainer."
     Fixed s -> liftIO $ initialize s
-  alignment <- liftIO $ simulateAlignment phyloModel tree alignmentLength gen
+  alignment <- liftIO $ simulateAlignment phyloModel t' alignmentLength gen
   let output = (sequencesToFasta . A.toSequences) alignment
   $(logInfo) ""
   out "simulated multi sequence alignment" output ".fasta"
diff --git a/src/SLynx/SubSample/Options.hs b/src/SLynx/SubSample/Options.hs
--- a/src/SLynx/SubSample/Options.hs
+++ b/src/SLynx/SubSample/Options.hs
@@ -1,44 +1,40 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.SubSample.Options
-Description :  ELynxSeq argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
--}
-
+-- |
+-- Module      :  SLynx.SubSample.Options
+-- Description :  ELynxSeq argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
 module SLynx.SubSample.Options
-  ( SubSampleArguments(..)
-  , subSampleArguments
-  , getOutSuffixes
+  ( SubSampleArguments (..),
+    subSampleArguments,
+    getOutSuffixes,
   )
 where
 
-import           Options.Applicative
-import qualified Data.Text                     as T
-import qualified Data.Text.Lazy                as LT
-import qualified Data.Text.Lazy.Builder        as LT
-import qualified Data.Text.Lazy.Builder.Int    as LT
-
-import           SLynx.Tools
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Tools
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.Builder as LT
+import qualified Data.Text.Lazy.Builder.Int as LT
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Tools
 
 -- | Data structure holding the Command line arguments.
 data SubSampleArguments = SubSampleArguments
-    { ssAlphabet    :: Alphabet
-    , ssInFile      :: FilePath
-    , ssNSites      :: Int
-    , ssNAlignments :: Int
-    , ssMbSeed      :: Seed }
+  { ssAlphabet :: Alphabet,
+    ssInFile :: FilePath,
+    ssNSites :: Int,
+    ssNAlignments :: Int,
+    ssMbSeed :: Seed
+  }
   deriving (Eq, Show, Generic)
 
 -- | Get a given number of output file suffixes.
@@ -48,21 +44,21 @@
 -- Will result in @.00.fasta@ up to @.10.fasta@.
 getOutSuffixes :: Int -> String -> [String]
 getOutSuffixes n suffix =
-  [ "." ++ digitStr i ++ "." ++ suffix | i <- [0 .. n - 1] ]
- where
-  nDigits = ceiling $ logBase (10 :: Double) (fromIntegral n)
-  digitStr i = T.unpack
-    $ T.justifyRight nDigits '0' (LT.toStrict $ LT.toLazyText $ LT.decimal i)
-
+  ["." ++ digitStr i ++ "." ++ suffix | i <- [0 .. n - 1]]
+  where
+    nDigits = ceiling $ logBase (10 :: Double) (fromIntegral n)
+    digitStr i =
+      T.unpack $
+        T.justifyRight nDigits '0' (LT.toStrict $ LT.toLazyText $ LT.decimal i)
 
 instance Reproducible SubSampleArguments where
   inFiles = pure . ssInFile
   outSuffixes a = getOutSuffixes (ssNAlignments a) "fasta"
   getSeed = Just . ssMbSeed
-  setSeed a s = a { ssMbSeed = Fixed s }
-  parser  = subSampleArguments
+  setSeed a s = a {ssMbSeed = Fixed s}
+  parser = subSampleArguments
   cmdName = "sub-sample"
-  cmdDsc  = ["Sub-sample columns from multi sequence alignments."]
+  cmdDsc = ["Sub-sample columns from multi sequence alignments."]
   cmdFtr =
     [ "Create a given number of multi sequence alignments, each of which contains a given number of random sites drawn from the original multi sequence alignment."
     ]
@@ -83,16 +79,18 @@
 
 subSampleNSitesOpt :: Parser Int
 subSampleNSitesOpt =
-  option auto $ long "number-of-sites" <> short 'n' <> metavar "INT" <> help
-    "Number of sites randomly drawn with replacement"
+  option auto $
+    long "number-of-sites" <> short 'n' <> metavar "INT"
+      <> help
+        "Number of sites randomly drawn with replacement"
 
 subSampleNAlignmentsOpt :: Parser Int
 subSampleNAlignmentsOpt =
-  option auto
-    $  long "number-of-alignments"
-    <> short 'm'
-    <> metavar "INT"
-    <> help "Number of multi sequence alignments to be created"
+  option auto $
+    long "number-of-alignments"
+      <> short 'm'
+      <> metavar "INT"
+      <> help "Number of multi sequence alignments to be created"
 
 filePathArg :: Parser FilePath
 filePathArg =
diff --git a/src/SLynx/SubSample/SubSample.hs b/src/SLynx/SubSample/SubSample.hs
--- a/src/SLynx/SubSample/SubSample.hs
+++ b/src/SLynx/SubSample/SubSample.hs
@@ -1,38 +1,33 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  Analyze.Analyze
-Description :  Parse sequence file formats and analyze them
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Oct  5 08:41:05 2018.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  Analyze.Analyze
+-- Description :  Parse sequence file formats and analyze them
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Oct  5 08:41:05 2018.
 module SLynx.SubSample.SubSample
-  ( subSampleCmd
+  ( subSampleCmd,
   )
 where
 
-import           Control.Monad
-import           Control.Monad.IO.Class
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Reader     ( ask )
-import qualified Data.Text                     as T
-import           System.Random.MWC
-
-import           SLynx.SubSample.Options
-import           SLynx.Tools
-
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Logger
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.Text as T
 import qualified ELynx.Data.Sequence.Alignment as M
-import           ELynx.Export.Sequence.Fasta
-import           ELynx.Tools
+import ELynx.Export.Sequence.Fasta
+import ELynx.Tools
+import SLynx.SubSample.Options
+import SLynx.Tools
+import System.Random.MWC
 
 -- | Sub sample sequences.
 subSampleCmd :: ELynx SubSampleArguments ()
@@ -40,15 +35,15 @@
   (SubSampleArguments al inFile nSites nAlignments (Fixed s)) <- local <$> ask
   $(logInfo) "Command: Sub sample from a multi sequence alignment."
   $(logInfo) $ T.pack $ "  Sample " <> show nSites <> " sites."
-  $(logInfo)
-    $  T.pack
-    $  "  Sample "
-    <> show nAlignments
-    <> " multi sequence alignments."
-  ss  <- readSeqs al inFile
+  $(logInfo) $
+    T.pack $
+      "  Sample "
+        <> show nAlignments
+        <> " multi sequence alignments."
+  ss <- readSeqs al inFile
   gen <- liftIO $ initialize s
   let a = either error id (M.fromSequences ss)
   samples <- liftIO $ replicateM nAlignments $ M.randomSubSample nSites a gen
   let results = map (sequencesToFasta . M.toSequences) samples
-      sfxs    = getOutSuffixes nAlignments "fasta"
+      sfxs = getOutSuffixes nAlignments "fasta"
   zipWithM_ (out "sub sampled multi sequence alignments") results sfxs
diff --git a/src/SLynx/Tools.hs b/src/SLynx/Tools.hs
--- a/src/SLynx/Tools.hs
+++ b/src/SLynx/Tools.hs
@@ -1,38 +1,36 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  SLynx.Tools
-Description :  Common tools for sequence lynx
-Copyright   :  (c) Dominik Schrempf 2020
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sat Sep  7 06:24:22 2019.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  SLynx.Tools
+-- Description :  Common tools for sequence lynx
+-- Copyright   :  (c) Dominik Schrempf 2020
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sat Sep  7 06:24:22 2019.
 module SLynx.Tools
   ( -- * SLynx.Tools
-    readSeqs
+    readSeqs,
+
     -- * Options
-  , alphabetOpt
+    alphabetOpt,
   )
 where
 
-import           Control.Monad.IO.Class
-import           Control.Monad.Logger
-import qualified Data.Text                     as T
-import           Options.Applicative
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Data.Sequence.Sequence
-import           ELynx.Import.Sequence.Fasta
-                                         hiding ( Parser )
-import           ELynx.Tools
+import Control.Monad.IO.Class
+import Control.Monad.Logger
+import qualified Data.Text as T
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Data.Sequence.Sequence
+import ELynx.Import.Sequence.Fasta hiding
+  ( Parser,
+  )
+import ELynx.Tools
+import Options.Applicative
 
 -- -- | Read sequences of given alphabet from file or standard input.
 -- readSeqs
@@ -58,17 +56,19 @@
 -- | Read sequences of given alphabet from file or standard input.
 readSeqs :: (MonadIO m, MonadLogger m) => Alphabet -> FilePath -> m [Sequence]
 readSeqs a fp = do
-  $(logInfo)
-    $  T.pack
-    $  "Read sequences from file "
-    <> fp
-    <> "; alphabet "
-    <> show a
-    <> "."
+  $(logInfo) $
+    T.pack $
+      "Read sequences from file "
+        <> fp
+        <> "; alphabet "
+        <> show a
+        <> "."
   liftIO $ parseFileWith (fasta a) fp
 
 -- | Command line option to specify the alphabet. Used by various commands.
 alphabetOpt :: Parser Alphabet
 alphabetOpt =
-  option auto $ long "alphabet" <> short 'a' <> metavar "NAME" <> help
-    "Specify alphabet type NAME"
+  option auto $
+    long "alphabet" <> short 'a' <> metavar "NAME"
+      <> help
+        "Specify alphabet type NAME"
diff --git a/src/SLynx/Translate/Options.hs b/src/SLynx/Translate/Options.hs
--- a/src/SLynx/Translate/Options.hs
+++ b/src/SLynx/Translate/Options.hs
@@ -1,40 +1,36 @@
 {-# LANGUAGE DeriveGeneric #-}
 
-{- |
-Module      :  SLynx.Translate.Options
-Description :  ELynxSeq argument parsing
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Sun Oct  7 17:29:45 2018.
-
--}
-
+-- |
+-- Module      :  SLynx.Translate.Options
+-- Description :  ELynxSeq argument parsing
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Sun Oct  7 17:29:45 2018.
 module SLynx.Translate.Options
-  ( TranslateArguments(..)
-  , translateArguments
+  ( TranslateArguments (..),
+    translateArguments,
   )
 where
 
-import           Data.List
-import           Options.Applicative
-
-import           SLynx.Tools
-
-import           ELynx.Data.Alphabet.Alphabet
-import           ELynx.Data.Character.Codon
-import           ELynx.Tools
+import Data.List
+import ELynx.Data.Alphabet.Alphabet
+import ELynx.Data.Character.Codon
+import ELynx.Tools
+import Options.Applicative
+import SLynx.Tools
 
 -- | Arguments needed to translate sequences.
 data TranslateArguments = TranslateArguments
-    { trAlphabet      :: Alphabet
-    , trInFile        :: FilePath
-    , trReadingFrame  :: Int
-    , trUniversalCode :: UniversalCode }
+  { trAlphabet :: Alphabet,
+    trInFile :: FilePath,
+    trReadingFrame :: Int,
+    trUniversalCode :: UniversalCode
+  }
   deriving (Eq, Show, Generic)
 
 instance Reproducible TranslateArguments where
@@ -42,9 +38,9 @@
   outSuffixes _ = [".fasta"]
   getSeed _ = Nothing
   setSeed = const
-  parser  = translateArguments
+  parser = translateArguments
   cmdName = "translate"
-  cmdDsc  = ["Translate from DNA to Protein or DNAX to ProteinX."]
+  cmdDsc = ["Translate from DNA to Protein or DNAX to ProteinX."]
 
 instance FromJSON TranslateArguments
 
@@ -61,17 +57,21 @@
 
 readingFrameOpt :: Parser Int
 readingFrameOpt =
-  option auto $ long "reading-frame" <> short 'r' <> metavar "INT" <> help
-    "Reading frame [0|1|2]."
+  option auto $
+    long "reading-frame" <> short 'r' <> metavar "INT"
+      <> help
+        "Reading frame [0|1|2]."
 
 universalCodeOpt :: Parser UniversalCode
 universalCodeOpt =
-  option auto $ long "universal-code" <> short 'u' <> metavar "CODE" <> help
-    ("universal code; one of: " ++ codeStr ++ ".")
- where
-  codes     = allValues :: [UniversalCode]
-  codeWords = map show codes
-  codeStr   = intercalate ", " codeWords
+  option auto $
+    long "universal-code" <> short 'u' <> metavar "CODE"
+      <> help
+        ("universal code; one of: " ++ codeStr ++ ".")
+  where
+    codes = allValues :: [UniversalCode]
+    codeWords = map show codes
+    codeStr = intercalate ", " codeWords
 
 inFileArg :: Parser FilePath
 inFileArg =
diff --git a/src/SLynx/Translate/Translate.hs b/src/SLynx/Translate/Translate.hs
--- a/src/SLynx/Translate/Translate.hs
+++ b/src/SLynx/Translate/Translate.hs
@@ -1,37 +1,32 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell   #-}
-
-{- |
-Module      :  Analyze.Analyze
-Description :  Parse sequence file formats and analyze them
-Copyright   :  (c) Dominik Schrempf 2018
-License     :  GPL-3.0-or-later
-
-Maintainer  :  dominik.schrempf@gmail.com
-Stability   :  unstable
-Portability :  portable
-
-Creation date: Fri Oct  5 08:41:05 2018.
-
--}
+{-# LANGUAGE TemplateHaskell #-}
 
+-- |
+-- Module      :  Analyze.Analyze
+-- Description :  Parse sequence file formats and analyze them
+-- Copyright   :  (c) Dominik Schrempf 2018
+-- License     :  GPL-3.0-or-later
+--
+-- Maintainer  :  dominik.schrempf@gmail.com
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- Creation date: Fri Oct  5 08:41:05 2018.
 module SLynx.Translate.Translate
-  ( translateCmd
+  ( translateCmd,
   )
 where
 
-import           Control.Monad.Logger
-import           Control.Monad.Trans.Reader     ( ask )
-import qualified Data.Text                     as T
-
-import           SLynx.Tools
-import           SLynx.Translate.Options
-
-import           ELynx.Data.Character.Codon
-import           ELynx.Data.Sequence.Sequence
-import           ELynx.Data.Sequence.Translate
-import           ELynx.Export.Sequence.Fasta
-import           ELynx.Tools
+import Control.Monad.Logger
+import Control.Monad.Trans.Reader (ask)
+import qualified Data.Text as T
+import ELynx.Data.Character.Codon
+import ELynx.Data.Sequence.Sequence
+import ELynx.Data.Sequence.Translate
+import ELynx.Export.Sequence.Fasta
+import ELynx.Tools
+import SLynx.Tools
+import SLynx.Translate.Options
 
 translateSeqs :: Int -> UniversalCode -> [Sequence] -> [Sequence]
 translateSeqs rf uc = map (translateSeq uc rf)
