diff --git a/kanji.cabal b/kanji.cabal
--- a/kanji.cabal
+++ b/kanji.cabal
@@ -1,90 +1,77 @@
--- This file has been generated from package.yaml by hpack version 0.28.2.
---
--- see: https://github.com/sol/hpack
---
--- hash: 18462ca584f835c151a09c99a797ee4947a3f928d05f706e3723007460f0e083
+cabal-version: 2.2
 
-name:           kanji
-version:        3.4.0
-synopsis:       Perform 漢字検定 (Japan Kanji Aptitude Test) level analysis on Japanese Kanji
-description:    Perform 漢字検定 (Japan Kanji Aptitude Test) level analysis on Japanese Kanji.
-category:       Data
-homepage:       https://github.com/fosskers/kanji
-author:         Colin Woodbury
-maintainer:     colingw@gmail.com
-copyright:      2011 - 2018 Colin Woodbury
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-cabal-version:  >= 1.10
+name:         kanji
+version:      3.4.0.1
+synopsis:     Perform 漢字検定 (Japan Kanji Aptitude Test) level analysis on Japanese Kanji
+description:  Perform 漢字検定 (Japan Kanji Aptitude Test) level analysis on Japanese Kanji.
+category:     Data
+homepage:     https://github.com/fosskers/kanji
+author:       Colin Woodbury
+maintainer:   colin@fosskers.ca
+copyright:    2011 - 2019 Colin Woodbury
+license:      BSD-3-Clause
+license-file: LICENSE
+build-type:   Simple
+
 extra-source-files:
-    CHANGELOG.md
-    README.md
+  README.md
+  CHANGELOG.md
 
+common commons
+  default-language: Haskell2010
+  build-depends:
+      base >= 4.7 && < 5
+    , aeson >= 1.2
+    , containers >= 0.5.8
+    , text
+  ghc-options:
+      -Wall
+      -Wincomplete-record-updates
+      -Wincomplete-uni-patterns
+      -Wredundant-constraints
+
 library
-  hs-source-dirs:
-      lib
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns
+  import: commons
+  hs-source-dirs: lib
   build-depends:
-      aeson >=1.2 && <1.4
-    , base >=4.7 && <5
-    , containers
-    , deepseq
+      deepseq
     , hashable
-    , text
   exposed-modules:
       Data.Kanji
       Data.Kanji.Levels
       Data.Kanji.Types
-  default-language: Haskell2010
 
 executable kanji
+  import: commons
   main-is: nanq.hs
-  hs-source-dirs:
-      nanq
-  default-extensions: OverloadedStrings
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -O2
+  hs-source-dirs: nanq
+  ghc-options: -O2
   build-depends:
-      aeson >=1.2 && <1.4
-    , aeson-pretty
-    , base >=4.7 && <5
-    , containers
+      aeson-pretty
     , kanji
-    , microlens >=0.4 && <0.5
-    , microlens-aeson >=2.2 && <2.4
-    , optparse-applicative >=0.14 && <0.15
-    , text
+    , microlens >=0.4
+    , microlens-aeson >=2.2
+    , optparse-applicative >=0.14
     , transformers
-  default-language: Haskell2010
 
 test-suite kanji-test
+  import: commons
   type: exitcode-stdio-1.0
   main-is: Test.hs
-  hs-source-dirs:
-      test
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -threaded
+  hs-source-dirs: test
+  ghc-options: -threaded -with-rtsopts=-N
   build-depends:
-      HUnit-approx >=1.1 && <1.2
-    , aeson >=1.2 && <1.4
-    , base >=4.7 && <5
-    , containers
+      HUnit-approx >=1.1
     , kanji
-    , tasty >=0.11 && <1.2
-    , tasty-hunit >=0.9 && <0.11
-    , text
-  default-language: Haskell2010
+    , tasty >=0.11
+    , tasty-hunit >=0.9
 
 benchmark kanji-bench
+  import: commons
   type: exitcode-stdio-1.0
   main-is: Bench.hs
-  hs-source-dirs:
-      bench
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -fwarn-incomplete-uni-patterns -threaded -O2
+  hs-source-dirs: bench
+  ghc-options: -threaded -O2
   build-depends:
-      aeson >=1.2 && <1.4
-    , base >=4.7 && <5
-    , containers
-    , criterion >=1.1 && <1.5
+      criterion >=1.1
     , kanji
-    , text
-  default-language: Haskell2010
diff --git a/lib/Data/Kanji.hs b/lib/Data/Kanji.hs
--- a/lib/Data/Kanji.hs
+++ b/lib/Data/Kanji.hs
@@ -2,43 +2,43 @@
 
 -- |
 -- Module    : Data.Kanji
--- Copyright : (c) Colin Woodbury, 2015 - 2018
+-- Copyright : (c) Colin Woodbury, 2015 - 2019
 -- License   : GPL3
--- Maintainer: Colin Woodbury <colingw@gmail.com>
+-- Maintainer: Colin Woodbury <colin@fosskers.ca>
 --
 -- A library for analysing the density of Kanji in given texts,
 -- according to their "Level" classification, as defined by the
 -- Japan Kanji Aptitude Testing Foundation (日本漢字能力検定協会).
 
 module Data.Kanji
-       (
-         -- * Kanji
-         Kanji
-       , kanji, _kanji
-       , allKanji
-       , isKanji, isHiragana, isKatakana
-         -- * Character Categories
-       , CharCat(..)
-       , category
-         -- * Levels
-       , Level(..)
-       , level
-         -- * Analysis
-       , percentSpread
-       , levelDist
-       , uniques
-         -- ** Densities
-       , densities
-       , elementaryDen
-       , middleDen
-       , highDen
-       ) where
+  (
+    -- * Kanji
+    Kanji
+  , kanji, _kanji
+  , allKanji
+  , isKanji, isHiragana, isKatakana
+    -- * Character Categories
+  , CharCat(..)
+  , category
+    -- * Levels
+  , Level(..)
+  , level
+    -- * Analysis
+  , percentSpread
+  , levelDist
+  , uniques
+    -- ** Densities
+  , densities
+  , elementaryDen
+  , middleDen
+  , highDen
+  ) where
 
 import           Control.Arrow hiding (second)
 import           Data.Foldable (fold)
 import           Data.Kanji.Levels
 import           Data.Kanji.Types
-import           Data.List (sort, group)
+import           Data.List (group, sort)
 import qualified Data.Map.Strict as M
 import           Data.Semigroup ((<>))
 import qualified Data.Set as S
diff --git a/lib/Data/Kanji/Levels.hs b/lib/Data/Kanji/Levels.hs
--- a/lib/Data/Kanji/Levels.hs
+++ b/lib/Data/Kanji/Levels.hs
@@ -1,8 +1,8 @@
 -- |
 -- Module    : Data.Kanji.Levels
--- Copyright : (c) Colin Woodbury, 2015 - 2018
+-- Copyright : (c) Colin Woodbury, 2015 - 2019
 -- License   : GPL3
--- Maintainer: Colin Woodbury <colingw@gmail.com>
+-- Maintainer: Colin Woodbury <colin@fosskers.ca>
 --
 -- All Kanji from levels 10 to Pre-2.
 
diff --git a/lib/Data/Kanji/Types.hs b/lib/Data/Kanji/Types.hs
--- a/lib/Data/Kanji/Types.hs
+++ b/lib/Data/Kanji/Types.hs
@@ -1,11 +1,12 @@
-{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
-{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric  #-}
+{-# LANGUAGE ViewPatterns   #-}
 
 -- |
 -- Module    : Data.Kanji.Types
 -- Copyright : (c) Colin Woodbury, 2015, 2016
 -- License   : GPL3
--- Maintainer: Colin Woodbury <colingw@gmail.com>
+-- Maintainer: Colin Woodbury <colin@fosskers.ca>
 --
 -- Types for this library. While a constructor for `Kanji` is made available
 -- here, you should prefer the `kanji` "smart constructor" unless you know
@@ -17,7 +18,7 @@
 import           Data.Aeson
 import           Data.Aeson.Encoding (text)
 import           Data.Bool (bool)
-import           Data.Char (ord, isLetter, isNumber, isPunctuation)
+import           Data.Char (isLetter, isNumber, isPunctuation, ord)
 import           Data.Hashable
 import qualified Data.Text as T
 import           GHC.Generics
diff --git a/nanq/nanq.hs b/nanq/nanq.hs
--- a/nanq/nanq.hs
+++ b/nanq/nanq.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TupleSections     #-}
 
 module Main ( main ) where
 
@@ -26,20 +27,22 @@
 
 data Operation = Density | Elementary | Distribution | Splits deriving (Eq)
 
-data Env = Env { _allKs :: [Kanji]
-               , _original :: Text } deriving Eq
+data Env = Env { _allKs :: [Kanji], _original :: Text } deriving Eq
 
 -- | Long, Short, Help
+lsh :: HasName f => String -> Char -> String -> Mod f a
 lsh l s h = long l <> short s <> help h
 
 flags :: Parser Flags
 flags = Flags <$> operations <*> (file <|> japanese)
-  where file = Left <$> strOption (lsh "file" 'f' "Take input from a file")
-        japanese = Right <$> argument str (metavar "JAPANESE")
+  where
+    file = Left <$> strOption (lsh "file" 'f' "Take input from a file")
+    japanese = Right <$> argument str (metavar "JAPANESE")
 
 operations :: Parser [Operation]
 operations = catMaybes <$> ops
-  where ops = traverse optional
+  where
+    ops = traverse optional
           [ flag' Density $
             lsh "density" 'd' "Find how much of the input is made of Kanji"
           , flag' Elementary $
@@ -55,7 +58,8 @@
 
 splits :: Reader Env Value
 splits = ob "levelSplit" . S.foldl' f mempty . S.fromList <$> asks _allKs
-  where f a k = (\l -> M.insertWith (++) l [k] a) $ level k
+  where
+    f a k = (\l -> M.insertWith (++) l [k] a) $ level k
 
 distribution :: Reader Env Value
 distribution = ob "distributions" . levelDist <$> asks _allKs
@@ -70,10 +74,10 @@
 
 -- | All operations return JSON, to be aggregated into a master Object.
 execOp :: Operation -> Reader Env Value
-execOp Density = density
-execOp Elementary = elementaryDensity
+execOp Density      = density
+execOp Elementary   = elementaryDensity
 execOp Distribution = distribution
-execOp Splits = splits
+execOp Splits       = splits
 
 output :: Value -> IO ()
 output = TLIO.putStrLn . toLazyText . encodePrettyToTextBuilder
@@ -81,15 +85,18 @@
 -- | Dispatch on each `Operation` given. Aggregates the resulting JSON.
 work :: (Env, [Operation]) -> Value
 work (e, os) = Object $ vals ^. each . _Object
-  where vals = runReader (traverse execOp os) e
+  where
+    vals = runReader (traverse execOp os) e
 
 env :: Flags -> IO (Env, [Operation])
 env (Flags os inp) = case inp of
   Right t -> pure (e t, os)
   Left  f -> (, os) . e <$> TIO.readFile f
-  where e t = Env (mapMaybe kanji $ T.unpack t) t
+  where
+    e t = Env (mapMaybe kanji $ T.unpack t) t
 
 main :: IO ()
 main = execParser opts >>= env >>= output . work
-  where opts = info (helper <*> flags)
-          (fullDesc <> header "nanq - Kanji analysis of Japanese text")
+  where
+    opts = info (helper <*> flags)
+           (fullDesc <> header "nanq - Kanji analysis of Japanese text")
