diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,6 +1,93 @@
 module Main where
 
-import Data.Text.WordCount.Exec
+import           Control.Arrow        ((&&&))
+import           Control.Lens         (over, _2)
+import           Data.Binary          (decode, encode)
+import qualified Data.ByteString      as BS
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.IntMap          as IM
+import           Data.Maybe
+import           Data.Monoid
+import qualified Data.Text.IO         as TIO
+import qualified Data.Text.Lazy       as TL
+import           Data.Text.WordCount
+import           Data.Version
+import           Options.Applicative
+import           Paths_wordchoice
+import           System.Directory     (doesFileExist)
 
+-- | Program datatype to be parsed
+data Program = Program { file         :: FilePath
+                       , num          :: Maybe Int
+                       , output       :: Maybe FilePath
+                       , filterOutput :: Bool
+                       , cacheIndex   :: Bool
+                       } -- TODO add option for separators
+
+-- | Command line argument parser
+program :: Parser Program
+program = Program
+    <$> (argument str
+        (metavar "FILEPATH"
+        <> completer (bashCompleter "file -o plusdirs")
+        <> help "File to analyze"))
+    <*> (optional (read <$> strOption
+        (short 'n'
+        <> long "number"
+        <>  metavar "NUM"
+        <> help "Top NUM words will be listed")))
+    <*> (optional (strOption
+        (short 'o'
+        <> long "output"
+        <>  metavar "OUTPUT"
+        <> help "Filepath for output graph")))
+    <*> switch
+        (short 'f'
+        <> long "filter"
+        <> help "Filter common English words from output.")
+    <*> switch
+        (short 'd'
+        <> long "dump"
+        <> help "Cache word frequency indices")
+
+-- | Parse for version info
+versionInfo :: Parser (a -> a)
+versionInfo = infoOption
+    ("wordchoice version: " <> showVersion version)
+    (short 'v' <> long "version" <> help "Show version")
+
+-- | Wraps parser with help parser
+wrapper :: ParserInfo Program
+wrapper = info (helper <*> versionInfo <*> program)
+    (fullDesc
+    <> progDesc "Word choice is a command-line meant to help you improve your writing. Simply point it to a file containing text and it will list your most frequently used words and their frequencies."
+    <> header "Word choice command-line utility")
+
+-- | Actual executable
 main :: IO ()
-main = exec
+main = execParser wrapper >>= pick
+
+-- | Run parsed record
+pick :: Program -> IO ()
+pick rec = do
+    let n = fromMaybe 25 (num rec)
+    contents <- TL.fromStrict <$> globFile (file rec)
+    pickContents <- case (filterOutput &&& num) rec of {
+        (True, _)        -> pure $ filterTop n small contents ;
+        (False, Just x)  -> pure $ topN x contents ;
+        (False, Nothing) -> do {
+            cacheExists <- doesFileExist "index.bin" ;
+            let toDisplay = (>>= (\(i, ws) -> zip (repeat i) ws)) in
+            if cacheExists
+                then toDisplay . IM.toList . (decode :: BSL.ByteString -> IM.IntMap [TL.Text]) . BSL.fromStrict <$> BS.readFile "index.bin"
+                else pure . toDisplay . IM.toList . indexed $ contents }
+        }
+    if cacheIndex rec
+        then do {
+            BS.writeFile "index.bin" . BSL.toStrict $ encode $ indexed contents ;
+            putStrLn "...finished indexing" ;
+            TIO.putStrLn . displayWords $ pickContents }
+        else TIO.putStrLn . displayWords $ pickContents
+    case output rec of
+        (Just out) -> flip makeFile out . topN n $ contents
+        _          -> pure ()
diff --git a/cabal.project.local b/cabal.project.local
--- a/cabal.project.local
+++ b/cabal.project.local
@@ -1,3 +1,2 @@
-constraints: wordchoice +fast-llvm
 with-compiler: ghc-8.2.2
 optimization: 2
diff --git a/src/Data/Text/WordCount.hs b/src/Data/Text/WordCount.hs
--- a/src/Data/Text/WordCount.hs
+++ b/src/Data/Text/WordCount.hs
@@ -13,8 +13,6 @@
     -- * File processing with pandoc
     , processFile
     , globFile
-    -- * Low level-ish
-    , buildFreq
     -- * Keyed maps
     , indexed
     ) where
diff --git a/src/Data/Text/WordCount/Exec.hs b/src/Data/Text/WordCount/Exec.hs
deleted file mode 100644
--- a/src/Data/Text/WordCount/Exec.hs
+++ /dev/null
@@ -1,96 +0,0 @@
-module Data.Text.WordCount.Exec where
-
-import           Control.Arrow                ((&&&))
-import           Control.Lens                 (over, _2)
-import           Data.Binary                  (decode, encode)
-import qualified Data.ByteString              as BS
-import qualified Data.ByteString.Lazy         as BSL
-import qualified Data.IntMap                  as IM
-import           Data.Maybe
-import           Data.Monoid
-import qualified Data.Text.IO                 as TIO
-import qualified Data.Text.Lazy               as TL
-import           Data.Text.WordCount
-import           Data.Text.WordCount.FileRead
-import           Data.Version
-import           Options.Applicative
-import           Paths_wordchoice
-import           System.Directory             (doesFileExist)
-
--- | Program datatype to be parsed
-data Program = Program { file         :: FilePath
-                       , num          :: Maybe Int
-                       , output       :: Maybe FilePath
-                       , filterOutput :: Bool
-                       , cacheIndex   :: Bool
-                       } -- TODO add option for separators
-
--- | Command line argument parser
-program :: Parser Program
-program = Program
-    <$> (argument str
-        (metavar "FILEPATH"
-        <> completer (bashCompleter "file -o plusdirs")
-        <> help "File to analyze"))
-    <*> (optional (read <$> strOption
-        (short 'n'
-        <> long "number"
-        <>  metavar "NUM"
-        <> help "Top NUM words will be listed")))
-    <*> (optional (strOption
-        (short 'o'
-        <> long "output"
-        <>  metavar "OUTPUT"
-        <> help "Filepath for output graph")))
-    <*> switch
-        (short 'f'
-        <> long "filter"
-        <> help "Filter common English words from output.")
-    <*> switch
-        (short 'd'
-        <> long "dump"
-        <> help "Cache word frequency indices")
-
--- | Parse for version info
-versionInfo :: Parser (a -> a)
-versionInfo = infoOption
-    ("wordchoice version: " <> showVersion version)
-    (short 'v' <> long "version" <> help "Show version")
-
--- | Wraps parser with help parser
-wrapper :: ParserInfo Program
-wrapper = info (helper <*> versionInfo <*> program)
-    (fullDesc
-    <> progDesc "Word choice is a command-line meant to help you improve your writing. Simply point it to a file containing text and it will list your most frequently used words and their frequencies."
-    <> header "Word choice command-line utility")
-
--- | Actual executable
-exec :: IO ()
-exec = execParser wrapper >>= pick
-
--- TODO stream output nicely?
-
--- | Run parsed record
-pick :: Program -> IO ()
-pick rec = do
-    let n = fromMaybe 25 (num rec)
-    contents <- TL.fromStrict <$> globFile (file rec)
-    pickContents <- case (filterOutput &&& num) rec of {
-        (True, _)        -> pure $ filterTop n small contents ;
-        (False, Just x)  -> pure $ topN x contents ;
-        (False, Nothing) -> do {
-            cacheExists <- doesFileExist "index.bin" ;
-            let toDisplay = (>>= (\(i, ws) -> zip (repeat i) ws)) in
-            if cacheExists
-                then toDisplay . IM.toList . (decode :: BSL.ByteString -> IM.IntMap [TL.Text]) . BSL.fromStrict <$> BS.readFile "index.bin"
-                else pure . toDisplay . IM.toList . indexed $ contents }
-        }
-    if cacheIndex rec
-        then do {
-            BS.writeFile "index.bin" . BSL.toStrict $ encode $ indexed contents ;
-            putStrLn "...finished indexing" ;
-            TIO.putStrLn . displayWords $ pickContents }
-        else TIO.putStrLn . displayWords $ pickContents
-    case output rec of
-        (Just out) -> flip makeFile out . topN n $ contents
-        _          -> pure ()
diff --git a/src/Data/Text/WordCount/FileRead.hs b/src/Data/Text/WordCount/FileRead.hs
--- a/src/Data/Text/WordCount/FileRead.hs
+++ b/src/Data/Text/WordCount/FileRead.hs
@@ -1,5 +1,7 @@
 -- | Module with function to read file in with pandoc and discard everything superfluous.
-module Data.Text.WordCount.FileRead where
+module Data.Text.WordCount.FileRead ( processFile
+                                    , globFile
+                                    ) where
 
 import           Control.Monad             ((<=<))
 import           Control.Monad.IO.Class    (liftIO)
diff --git a/wordchoice.cabal b/wordchoice.cabal
--- a/wordchoice.cabal
+++ b/wordchoice.cabal
@@ -1,6 +1,6 @@
 cabal-version: >=1.10
 name: wordchoice
-version: 0.1.2.5
+version: 0.1.2.6
 license: BSD3
 license-file: LICENSE
 copyright: 2017,2018 Vanessa McHale
@@ -23,11 +23,9 @@
 library
     exposed-modules:
         Data.Text.WordCount
-        Data.Text.WordCount.Exec
-    hs-source-dirs: src
     other-modules:
-        Paths_wordchoice
         Data.Text.WordCount.FileRead
+    hs-source-dirs: src
     default-language: Haskell2010
     default-extensions: OverloadedStrings
     build-depends:
@@ -39,7 +37,6 @@
         binary -any,
         text -any,
         directory -any,
-        optparse-applicative -any,
         composition-prelude -any,
         Chart -any,
         bytestring -any,
@@ -50,10 +47,19 @@
 
 executable wrd
     main-is: Main.hs
+    other-modules:
+        Paths_wordchoice
     hs-source-dirs: app
     default-language: Haskell2010
     build-depends:
         base -any,
+        optparse-applicative -any,
+        directory -any,
+        bytestring -any,
+        binary -any,
+        containers -any,
+        lens -any,
+        text -any,
         wordchoice -any
 
 test-suite wordchoice-test
@@ -71,7 +77,6 @@
     main-is: Bench.hs
     hs-source-dirs: bench
     default-language: Haskell2010
-    ghc-options: -O2
     build-depends:
         base -any,
         criterion -any,
