diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,7 +2,14 @@
 # Changelog for ELynx
 
 
-## Version 0.3.1; in development
+## Version 0.3.2; in development
+
+
+## Version 0.3.1
+
+-   Use Attoparsec.
+-   Use ByteString consistently.
+-   Remove elynx-tools dependency from libaries.
 
 
 ## Version 0.3.0
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 # The ELynx Suite
 
-Version: 0.3.0.
+Version: 0.3.1.
 Reproducible evolution made easy.
 
 <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>
@@ -90,9 +90,9 @@
 
     slynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -136,9 +136,9 @@
 
     slynx concatenate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE
       Concatenate sequences found in input files.
@@ -157,9 +157,9 @@
 
     slynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site]
       Examine sequences. If data is a multi sequence alignment, additionally analyze columns.
@@ -179,9 +179,9 @@
 
     slynx filter-rows --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] 
                              [--shorter-than LENGTH] [--standard-characters]
@@ -202,9 +202,9 @@
 
     slynx filter-columns --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE 
                                 [--standard-chars DOUBLE]
@@ -226,9 +226,9 @@
 
     slynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] 
                           [-m|--mixture-model MODEL] [-e|--edm-file NAME] 
@@ -305,9 +305,9 @@
 
     slynx sub-sample --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE
                             (-n|--number-of-sites INT)
@@ -335,9 +335,9 @@
 
     slynx translate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT)
                            (-u|--universal-code CODE)
@@ -360,9 +360,9 @@
 
     tlynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -399,9 +399,9 @@
 
     tlynx compare --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] 
                          [-f|--newick-format FORMAT] NAMES
@@ -428,9 +428,9 @@
 
     tlynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT]
       Compute summary statistics of phylogenetic trees.
@@ -452,9 +452,9 @@
 
     tlynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE] 
                           [-M|--condition-on-mrca] [-l|--lambda DOUBLE] 
@@ -491,9 +491,9 @@
 
     elynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: elynx COMMAND
       Validate and redo past ELynx analyses
diff --git a/src/TLynx/Coalesce/Coalesce.hs b/src/TLynx/Coalesce/Coalesce.hs
--- a/src/TLynx/Coalesce/Coalesce.hs
+++ b/src/TLynx/Coalesce/Coalesce.hs
@@ -28,8 +28,8 @@
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
 import Control.Parallel.Strategies
-import qualified Data.ByteString.Builder as L
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.Maybe
 import qualified Data.Sequence as Seq
 import qualified Data.Text as T
@@ -60,7 +60,7 @@
         if s
           then parMap rpar (formatNChildSumStat . toNChildSumStat) trs
           else parMap rpar toNewick (map lengthToPhyloTree trs)
-  let res = L.unlines ls
+  let res = BL.unlines ls
   out "simulated trees" res ".tree"
 
 simulateNTreesConcurrently :: ELynx CoalesceArguments (Forest Length Int)
@@ -126,13 +126,13 @@
 --    nLeaves1 branchLength1
 --    nLeaves2 branchLength2
 --    ....
-formatNChildSumStat :: NChildSumStat -> L.ByteString
+formatNChildSumStat :: NChildSumStat -> BL.ByteString
 formatNChildSumStat s =
-  L.toLazyByteString . mconcat $ map formatNChildSumStatLine s
+  BB.toLazyByteString . mconcat $ map formatNChildSumStatLine s
 
-formatNChildSumStatLine :: BrLnNChildren -> L.Builder
+formatNChildSumStatLine :: BrLnNChildren -> BB.Builder
 formatNChildSumStatLine (l, n) =
-  L.intDec n <> L.char8 ' ' <> L.doubleDec l <> L.char8 '\n'
+  BB.intDec n <> BB.char8 ' ' <> BB.doubleDec l <> BB.char8 '\n'
 
 -- | Compute NChilSumStat for a phylogenetic tree.
 toNChildSumStat :: Measurable e => Tree e a -> NChildSumStat
diff --git a/src/TLynx/Compare/Compare.hs b/src/TLynx/Compare/Compare.hs
--- a/src/TLynx/Compare/Compare.hs
+++ b/src/TLynx/Compare/Compare.hs
@@ -21,8 +21,8 @@
 import Control.Monad.IO.Class
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import Data.ByteString.Lazy.Char8 (ByteString)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.List (intercalate)
 import qualified Data.Map as M
 import qualified Data.Set as S
@@ -48,7 +48,7 @@
   FilePath ->
   ELynx
     CompareArguments
-    (Tree PhyloStrict ByteString, Tree PhyloStrict ByteString)
+    (Tree PhyloStrict BS.ByteString, Tree PhyloStrict BS.ByteString)
 treesOneFile tf = do
   nwF <- argsNewickFormat . local <$> ask
   $(logInfo) $ T.pack $ "Parse file '" ++ tf ++ "'."
@@ -68,7 +68,7 @@
   FilePath ->
   ELynx
     CompareArguments
-    (Tree PhyloStrict ByteString, Tree PhyloStrict ByteString)
+    (Tree PhyloStrict BS.ByteString, Tree PhyloStrict BS.ByteString)
 treesTwoFiles tf1 tf2 = do
   nwF <- argsNewickFormat . local <$> ask
   $(logInfo) $ T.pack $ "Parse first tree file '" ++ tf1 ++ "'."
@@ -93,9 +93,9 @@
       error
         "Need two input files with one tree each or one input file with two trees."
   liftIO $ hPutStrLn outH "Tree 1:"
-  liftIO $ L.hPutStrLn outH $ toNewick $ fromStrictTree tr1
+  liftIO $ BL.hPutStrLn outH $ toNewick $ fromStrictTree tr1
   liftIO $ hPutStrLn outH "Tree 2:"
-  liftIO $ L.hPutStrLn outH $ toNewick $ fromStrictTree tr2
+  liftIO $ BL.hPutStrLn outH $ toNewick $ fromStrictTree tr2
   liftIO $ hPutStrLn outH ""
   -- Intersect trees.
   (t1, t2) <-
@@ -103,8 +103,8 @@
       then do
         let [x, y] = either error id $ intersect [tr1, tr2]
         liftIO $ hPutStrLn outH "Intersected trees are:"
-        liftIO $ L.hPutStrLn outH $ toNewick $ fromStrictTree x
-        liftIO $ L.hPutStrLn outH $ toNewick $ fromStrictTree y
+        liftIO $ BL.hPutStrLn outH $ toNewick $ fromStrictTree x
+        liftIO $ BL.hPutStrLn outH $ toNewick $ fromStrictTree y
         return (x, y)
       else return (tr1, tr2)
   -- Check input (moved to library functions).
@@ -135,8 +135,8 @@
   let t1' = normalizeBranchSupport t1
       t2' = normalizeBranchSupport t2
   $(logDebug) "Trees with normalized branch support values:"
-  $(logDebug) $ E.decodeUtf8 $ L.toStrict $ toNewick $ fromStrictTree t1'
-  $(logDebug) $ E.decodeUtf8 $ L.toStrict $ toNewick $ fromStrictTree t2'
+  $(logDebug) $ E.decodeUtf8 $ BL.toStrict $ toNewick $ fromStrictTree t1'
+  $(logDebug) $ E.decodeUtf8 $ BL.toStrict $ toNewick $ fromStrictTree t2'
   liftIO $
     T.hPutStrLn outH $
       formatD
@@ -168,14 +168,14 @@
         (T.pack $ show $ incompatibleSplits (collapse 0.9 t1') (collapse 0.9 t2'))
   -- liftIO $ T.hPutStrLn outH $ formatD "Incompatible split (1.01)"
   --   (T.pack $ show $ incompatibleSplits (collapse 1.01 t1') (collapse 1.01 t2'))
-  -- liftIO $ L.hPutStrLn outH $ toNewick (collapse 1.01 t1')
+  -- liftIO $ BL.hPutStrLn outH $ toNewick (collapse 1.01 t1')
 
   -- Bipartitions.
   when
     (argsBipartitions l)
     ( do
-        let bp1 = either error id $ bipartitions (fmap getName t1)
-            bp2 = either error id $ bipartitions (fmap getName t2)
+        let bp1 = either error id $ bipartitions t1
+            bp2 = either error id $ bipartitions t2
             bp1Only = bp1 S.\\ bp2
             bp2Only = bp2 S.\\ bp1
         unless
@@ -184,10 +184,10 @@
               liftIO $ hPutStrLn outH ""
               liftIO $
                 hPutStrLn outH "Bipartitions in Tree 1 that are not in Tree 2."
-              -- let bp1Strs = map (bphuman L.unpack . bpmap getName) (S.toList bp1Only)
+              -- let bp1Strs = map (bphuman BL.unpack . bpmap getName) (S.toList bp1Only)
               forM_ bp1Only (liftIO . hPutStrLn outH . bpHuman)
           )
-        -- let bp1Strs = map (bphuman L.unpack) (S.toList bp1Only)
+        -- let bp1Strs = map (bphuman BL.unpack) (S.toList bp1Only)
         -- liftIO $ hPutStrLn outH $ intercalate "\n" bp1Strs)
         unless
           (S.null bp2Only)
diff --git a/src/TLynx/Connect/Connect.hs b/src/TLynx/Connect/Connect.hs
--- a/src/TLynx/Connect/Connect.hs
+++ b/src/TLynx/Connect/Connect.hs
@@ -20,8 +20,8 @@
 import Control.Monad.IO.Class
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import Data.ByteString.Lazy.Char8 (ByteString)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy.Char8 as BL
 import qualified Data.Set as S
 import ELynx.Data.Tree
 import ELynx.Export.Tree.Newick (toNewick)
@@ -73,9 +73,9 @@
   liftIO $ hClose outH
 
 connectTrees ::
-  Tree Length ByteString ->
-  Tree Length ByteString ->
-  Forest Length ByteString
+  Tree Length BS.ByteString ->
+  Tree Length BS.ByteString ->
+  Forest Length BS.ByteString
 connectTrees t = either error id . connect 0 "root" t
 
 type Constraint a = S.Set a
@@ -106,7 +106,7 @@
   FilePath ->
   ELynx
     ConnectArguments
-    (Tree Length ByteString, Tree Length ByteString)
+    (Tree Length BS.ByteString, Tree Length BS.ByteString)
 parseTrees l r = do
   nwF <- nwFormat . local <$> ask
   tl <- liftIO $ parseFileWith (oneNewick nwF) l
@@ -122,7 +122,7 @@
   (tl, tr) <- parseTrees l r
   let ts = connectTrees tl tr
   $(logInfo) $ "Connected trees: " <> tShow (length ts)
-  liftIO $ L.hPutStr h $ L.unlines $ map (toNewick . lengthToPhyloTree) ts
+  liftIO $ BL.hPutStr h $ BL.unlines $ map (toNewick . lengthToPhyloTree) ts
 
 connectAndFilter ::
   Handle -> FilePath -> FilePath -> FilePath -> ELynx ConnectArguments ()
@@ -130,12 +130,12 @@
   nwF <- nwFormat . local <$> ask
   cts <- liftIO $ parseFileWith (someNewick nwF) c
   $(logInfo) "Constraints:"
-  $(logInfo) $ fromBs $ L.intercalate "\n" $ map toNewick cts
+  $(logInfo) $ fromBs $ BL.intercalate "\n" $ map toNewick cts
   (tl, tr) <- parseTrees l r
   let ts = connectTrees tl tr
-      cs = map S.fromList $ concatMap multifurcatingGroups cts :: [Constraint ByteString]
+      cs = map S.fromList $ concatMap multifurcatingGroups cts :: [Constraint BS.ByteString]
       -- Only collect trees that are compatible with the constraints.
       ts' = filter (compatibleWith getName cs) ts
   $(logInfo) $ "Connected  trees: " <> tShow (length ts)
   $(logInfo) $ "Compatible trees: " <> tShow (length ts')
-  liftIO $ L.hPutStr h $ L.unlines $ map (toNewick . lengthToPhyloTree) ts'
+  liftIO $ BL.hPutStr h $ BL.unlines $ map (toNewick . lengthToPhyloTree) ts'
diff --git a/src/TLynx/Distance/Distance.hs b/src/TLynx/Distance/Distance.hs
--- a/src/TLynx/Distance/Distance.hs
+++ b/src/TLynx/Distance/Distance.hs
@@ -31,9 +31,11 @@
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.Reader hiding (local)
 import Data.Bifunctor
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.List hiding (intersect)
 import Data.Maybe
+-- TODO: Remove text dependency.
 import qualified Data.Text as T
 import qualified Data.Text.IO as T
 import qualified Data.Text.Lazy as LT
@@ -54,20 +56,20 @@
 pf :: String
 pf = "%.3f"
 
-header :: Int -> Int -> DistanceMeasure -> L.ByteString
+header :: Int -> Int -> DistanceMeasure -> BL.ByteString
 header n m d =
   alignLeft (n + 2) "Tree 1" <> alignLeft (n + 2) "Tree 2"
     <> alignRight
       (m + 2)
-      (L.pack $ show d)
+      (BL.pack $ show d)
 
 showTriplet ::
-  (PrintfArg a) => Int -> Int -> [String] -> (Int, Int, a) -> L.ByteString
+  (PrintfArg a) => Int -> Int -> [String] -> (Int, Int, a) -> BL.ByteString
 showTriplet n m args (i, j, d) = i' <> j' <> d'
   where
-    i' = alignLeft (n + 2) $ L.pack (args !! i)
-    j' = alignLeft (n + 2) $ L.pack (args !! j)
-    d' = alignRight (m + 2) $ L.pack (printf pf d)
+    i' = alignLeft (n + 2) $ BL.pack (args !! i)
+    j' = alignLeft (n + 2) $ BL.pack (args !! j)
+    d' = alignRight (m + 2) $ BL.pack (printf pf d)
 
 -- Compute pairwise distances of a list of input trees. Use given distance
 -- measure. Returns a triple, the first two elements are the indices of the
@@ -132,7 +134,7 @@
   -- when (isNothing mtree) $ $(logInfo)
   --   "Compute pairwise distances between trees from different files."
   $(logDebug) "The trees are:"
-  $(logDebug) $ LT.toStrict $ LT.decodeUtf8 $ L.unlines $ map toNewick trees
+  $(logDebug) $ LT.toStrict $ LT.decodeUtf8 $ BL.unlines $ map toNewick trees
   -- Set the distance measure.
   let dist = argsDistance l
   case argsDistance l of
@@ -147,8 +149,8 @@
     BranchScore -> $(logInfo) "Use branch score distance."
   let distanceMeasure' ::
         (Measurable e1, Measurable e2) =>
-        Tree e1 L.ByteString ->
-        Tree e2 L.ByteString ->
+        Tree e1 BS.ByteString ->
+        Tree e2 BS.ByteString ->
         Double
       distanceMeasure' t1 t2 = either error id $ case dist of
         Symmetric -> second fromIntegral $ symmetric t1 t2
@@ -177,10 +179,10 @@
         IncompatibleSplit val -> collapse val . normalizeBranchSupport
         _ -> id
   -- The trees can be prepared now.
-  let trees' :: Forest PhyloStrict L.ByteString
+  let trees' :: Forest PhyloStrict BS.ByteString
       trees' = map (collapseF . normalizeF . either error id . toStrictTree) trees
   $(logDebug) "The prepared trees are:"
-  $(logDebug) $ LT.toStrict $ LT.decodeUtf8 $ L.unlines $ map (toNewick . fromStrictTree) trees'
+  $(logDebug) $ LT.toStrict $ LT.decodeUtf8 $ BL.unlines $ map (toNewick . fromStrictTree) trees'
   let dsTriplets = case mtree of
         Nothing -> pairwise distanceMeasure trees'
         Just pt ->
@@ -208,9 +210,9 @@
       T.justifyLeft 10 ' ' "Variance: "
         <> T.pack
           (printf pf (variance dsVec))
-  -- L.putStrLn $ L.unlines $ map toNewick ts
-  -- L.putStrLn $ L.unlines $ map toNewick tsN
-  -- L.putStrLn $ L.unlines $ map toNewick tsC
+  -- BS.putStrLn $ BS.unlines $ map toNewick ts
+  -- BS.putStrLn $ BS.unlines $ map toNewick tsN
+  -- BS.putStrLn $ BS.unlines $ map toNewick tsC
 
   lift $
     unless
@@ -219,17 +221,17 @@
           let n = maximum $ 6 : map length names
               m = length $ show dist
           lift $ hPutStrLn outH ""
-          lift $ L.hPutStrLn outH $ header n m dist
+          lift $ BL.hPutStrLn outH $ header n m dist
           case mname of
             Nothing ->
               lift $
-                L.hPutStr outH $
-                  L.unlines
+                BL.hPutStr outH $
+                  BL.unlines
                     (map (showTriplet n m names) dsTriplets)
             Just mn ->
               lift $
-                L.hPutStr outH $
-                  L.unlines
+                BL.hPutStr outH $
+                  BL.unlines
                     (map (showTriplet n m (mn : names)) dsTriplets)
       )
   liftIO $ hClose outH
diff --git a/src/TLynx/Distance/Options.hs b/src/TLynx/Distance/Options.hs
--- a/src/TLynx/Distance/Options.hs
+++ b/src/TLynx/Distance/Options.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 -- |
 -- Module      :  TLynx.Distance.Options
@@ -19,21 +20,11 @@
   )
 where
 
-import Data.Scientific (toRealFloat)
-import Data.Void
+import qualified Data.Attoparsec.ByteString.Char8 as AC
+import qualified Data.ByteString.Char8 as BS
 import ELynx.Tools
 import Options.Applicative
 import TLynx.Parsers
-import Text.Megaparsec
-  ( Parsec,
-    eof,
-    try,
-  )
-import Text.Megaparsec.Char
-  ( char,
-    string,
-  )
-import Text.Megaparsec.Char.Lexer (scientific)
 import Text.Printf
 
 -- | Supported distance measures.
@@ -112,38 +103,41 @@
       <> help
         "Read tree(s) from INPUT-FILES; if more files are given, one tree is expected per file"
 
-symmetric :: Parsec Void String DistanceMeasure
+symmetric :: AC.Parser DistanceMeasure
 symmetric = do
-  _ <- string "symmetric"
-  _ <- eof
+  _ <- AC.string "symmetric"
+  _ <- AC.endOfInput
   pure Symmetric
 
-incompatibleSplit :: Parsec Void String DistanceMeasure
+incompatibleSplit :: AC.Parser DistanceMeasure
 incompatibleSplit = do
-  _ <- string "incompatible-split"
-  _ <- char '['
-  f <- toRealFloat <$> scientific
-  _ <- char ']'
-  _ <- eof
+  _ <- AC.string "incompatible-split"
+  _ <- AC.char '['
+  f <- AC.double
+  _ <- AC.char ']'
+  _ <- AC.endOfInput
   if (0 <= f) && (f <= 1)
     then pure $ IncompatibleSplit f
     else error "Branch support has to be in [0, 1]."
 
-branchScore :: Parsec Void String DistanceMeasure
+branchScore :: AC.Parser DistanceMeasure
 branchScore = do
-  _ <- string "branch-score"
-  _ <- eof
+  _ <- AC.string "branch-score"
+  _ <- AC.endOfInput
   pure BranchScore
 
-distanceParser :: Parsec Void String DistanceMeasure
-distanceParser =
-  -- Try first the normalized one, since the normal branch score
-  -- parser also succeeds in this case.
-  try symmetric <|> try incompatibleSplit <|> branchScore
+-- Try first the normalized one, since the normal branch score
+-- parser also succeeds in this case.
+distanceParser :: AC.Parser DistanceMeasure
+distanceParser = symmetric <|> incompatibleSplit <|> branchScore
 
+-- See 'eitherReader', but for an attoparsec parser.
+eitherReadA :: AC.Parser a -> ReadM a
+eitherReadA p = eitherReader $ \input -> AC.parseOnly p (BS.pack input)
+
 distanceOpt :: Parser DistanceMeasure
 distanceOpt =
-  option (megaReadM distanceParser) $
+  option (eitherReadA distanceParser) $
     long "distance"
       <> short 'd'
       <> metavar "MEASURE"
diff --git a/src/TLynx/Examine/Examine.hs b/src/TLynx/Examine/Examine.hs
--- a/src/TLynx/Examine/Examine.hs
+++ b/src/TLynx/Examine/Examine.hs
@@ -20,7 +20,8 @@
 import Control.Monad.IO.Class
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.Containers.ListUtils (nubOrd)
 import Data.List ((\\))
 import qualified Data.Text as T
@@ -32,8 +33,33 @@
     hPutStrLn,
   )
 import TLynx.Examine.Options
+import Text.Printf
 
-readTrees :: FilePath -> ELynx ExamineArguments (Forest Phylo L.ByteString)
+pretty :: BranchLength -> String
+pretty = printf "%.5f"
+
+prettyRow :: String -> String -> BL.ByteString
+prettyRow name val = alignLeft 33 n <> alignRight 8 v
+  where
+    n = BL.pack name
+    v = BL.pack val
+
+-- | Examine branches of a tree.
+summarizeBranchLengths :: Measurable e => Tree e a -> BL.ByteString
+summarizeBranchLengths t =
+  BL.intercalate
+    "\n"
+    [ prettyRow "Origin height: " $ pretty h,
+      prettyRow "Mean distance origin leaves: " $ pretty h',
+      prettyRow "Total branch length: " $ pretty b
+    ]
+  where
+    n = length $ leaves t
+    h = height t
+    h' = sum (distancesOriginLeaves t) / fromIntegral n
+    b = totalBranchLength t
+
+readTrees :: FilePath -> ELynx ExamineArguments (Forest Phylo BS.ByteString)
 readTrees fp = do
   $(logInfo) $ T.pack $ "Read tree(s) from file " <> fp <> "."
   nf <- argsNewickFormat . local <$> ask
@@ -45,12 +71,13 @@
   let l = phyloToLengthTree t
   case l of
     Left _ -> hPutStrLn h "Branch lengths not available."
-    Right t' -> L.hPutStrLn h $ summarizeBranchLengths t'
+    Right t' -> BL.hPutStrLn h $ summarizeBranchLengths t'
   unless (null dups) $
     hPutStrLn h ""
       >> hPutStrLn
         h
         ("Duplicate leaves: " ++ show dups)
+  BL.hPutStrLn h $ "Leave names: " <> BL.intercalate " " lvs
   where
     lvs = map getName $ leaves t
     dups = lvs \\ nubOrd lvs
diff --git a/src/TLynx/Shuffle/Shuffle.hs b/src/TLynx/Shuffle/Shuffle.hs
--- a/src/TLynx/Shuffle/Shuffle.hs
+++ b/src/TLynx/Shuffle/Shuffle.hs
@@ -25,7 +25,7 @@
 import Control.Monad.IO.Class (liftIO)
 import Control.Monad.Logger (logDebug, logInfo)
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Lazy.Char8 as BL
 import ELynx.Data.Tree
 import ELynx.Export.Tree.Newick (toNewick)
 import ELynx.Import.Tree.Newick (oneNewick)
@@ -69,16 +69,16 @@
     Random -> error "Seed not available; please contact maintainer."
     Fixed s -> liftIO $ initialize s
   ts <- liftIO $ shuffleT (nReplicates l) (height t) cs ls gen
-  liftIO $ L.hPutStr h $ L.unlines $ map (toNewick . lengthToPhyloTree) ts
+  liftIO $ BL.hPutStr h $ BL.unlines $ map (toNewick . lengthToPhyloTree) ts
   liftIO $ hClose h
 
 shuffleT ::
   Int -> -- How many?
   Double -> -- Stem length.
   [Double] -> -- Coalescent times.
-  [L.ByteString] -> -- Leave names.
+  [BL.ByteString] -> -- Leave names.
   GenIO ->
-  IO (Forest Length L.ByteString)
+  IO (Forest Length BL.ByteString)
 shuffleT n o cs ls gen = do
   css <- grabble cs n (length cs) gen
   lss <- grabble ls n (length ls) gen
diff --git a/src/TLynx/Simulate/Simulate.hs b/src/TLynx/Simulate/Simulate.hs
--- a/src/TLynx/Simulate/Simulate.hs
+++ b/src/TLynx/Simulate/Simulate.hs
@@ -35,8 +35,8 @@
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
 import Control.Parallel.Strategies
-import qualified Data.ByteString.Builder as L
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.Foldable (toList)
 import Data.Maybe
 import qualified Data.Sequence as Seq
@@ -91,7 +91,7 @@
         if sumS
           then parMap rpar (formatNChildSumStat . toNChildSumStat) trs
           else parMap rpar toNewick $ map lengthToPhyloTree trs
-  let res = L.unlines ls
+  let res = BL.unlines ls
   out "simulated trees" res ".tree"
 
 simulateNTreesConcurrently ::
@@ -182,13 +182,13 @@
 --    nLeaves1 branchLength1
 --    nLeaves2 branchLength2
 --    ....
-formatNChildSumStat :: NChildSumStat -> L.ByteString
+formatNChildSumStat :: NChildSumStat -> BL.ByteString
 formatNChildSumStat s =
-  L.toLazyByteString . mconcat $ map formatNChildSumStatLine s
+  BB.toLazyByteString . mconcat $ map formatNChildSumStatLine s
 
-formatNChildSumStatLine :: BrLnNChildren -> L.Builder
+formatNChildSumStatLine :: BrLnNChildren -> BB.Builder
 formatNChildSumStatLine (l, n) =
-  L.intDec n <> L.char8 ' ' <> L.doubleDec l <> L.char8 '\n'
+  BB.intDec n <> BB.char8 ' ' <> BB.doubleDec l <> BB.char8 '\n'
 
 -- | Compute NChilSumStat for a phylogenetic tree.
 toNChildSumStat :: Measurable e => Tree e a -> NChildSumStat
diff --git a/tlynx.cabal b/tlynx.cabal
--- a/tlynx.cabal
+++ b/tlynx.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 4c935a10e73a1a6ec515b771ad749be8dcdb27e3daea89833fa5218ceafe0b47
+-- hash: f43d3e414f073da7967cef379f86a9accddecf157c0eb4dcfded3e6282fc8d8f
 
 name:           tlynx
-version:        0.3.0
+version:        0.3.1
 synopsis:       Handle phylogenetic trees
 description:    Examine, compare, and simulate phylogenetic trees in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
 category:       Bioinformatics
@@ -55,7 +55,7 @@
   ghc-options: -Wall -fllvm
   build-depends:
       aeson
-    , array
+    , attoparsec
     , base >=4.7 && <5
     , bytestring
     , comonad
@@ -64,13 +64,10 @@
     , elynx-tree
     , gnuplot
     , lifted-async
-    , megaparsec
     , monad-logger
     , mwc-random
     , optparse-applicative
     , parallel
-    , primitive
-    , scientific
     , statistics
     , text
     , transformers
@@ -86,6 +83,5 @@
   ghc-options: -Wall -fllvm -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
-    , elynx-tools
     , tlynx
   default-language: Haskell2010
