diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,22 @@
 
 # Changelog
 
+
+## [(diff)](https://github.com/haskell-nix/hnix/compare/0.10.1...0.11.0#files_bucket) 0.11.0 (2020-11-02)
+
+* Breaking:
+  * [(link)](https://github.com/haskell-nix/hnix/pull/740) Deleted incorrect `instance Generic1 NKeyName` from `module Nix.Expr.Types`.
+  * [(link)](https://github.com/haskell-nix/hnix/pull/739) Parentheses now are properly included in the location annotation for Nix expressions, change of `nixParens` in `module Nix.Parser` essentially results in the change of all module `nix*` function results, essentially making results of the whole module more proper.
+
+* Additional:
+  * [(link)](https://github.com/haskell-nix/hnix/pull/741) Fix QQ Text lifting error: work around of [GHC#12596 "can't find interface-file declaration"](https://gitlab.haskell.org/ghc/ghc/-/issues/12596).
+  * [(link)](https://github.com/haskell-nix/hnix/pull/744) Fix comments inclusion into location annotations, by using pre-whitespace position for source end locations.
+
+
 ### [(diff)](https://github.com/haskell-nix/hnix/compare/0.10.0...0.10.1#files_bucket) 0.10.1 (2020-09-13)
 
 * Additional:
-  * [(link)](https://github.com/haskell-nix/hnix/pull/715/files) `{Binding, NExpr, NExprF, NKeyName}` gained `Ord1` instances.
+  * [(link)](https://github.com/haskell-nix/hnix/pull/715) `{Binding, NExpr, NExprF, NKeyName}` gained `Ord1` instances.
     * These instances were required by downstream projects to be able to use newer HNix.
   * [(link)](https://github.com/haskell-nix/hnix/pull/712) CLI gained `--long-version` option for gathering a detailed debug information.
     * Currently, reports Git commit and its date.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,139 +1,262 @@
+[![Chatroom Gitter](https://img.shields.io/badge/Chatroom-Gitter-%23753a88)](https://gitter.im/haskell-nix/Lobby)
+[![Hackage](https://img.shields.io/hackage/v/hnix?color=%235e5086&label=Latest%20release%20on%20Hackage)](https://hackage.haskell.org/package/hnix)
+[![Hackage Matrix Builder](https://img.shields.io/badge/Hackage%20Matrix-Builder-%235e5086)](https://matrix.hackage.haskell.org/package/hnix)
+[![Bounds](https://img.shields.io/hackage-deps/v/hnix?label=Released%20dep%20bounds)](https://packdeps.haskellers.com/feed?needle=hnix)
+[![Hydra CI](https://img.shields.io/badge/Nixpkgs%20Hydra-CI-%234f72bb)](https://hydra.nixos.org/job/nixpkgs/trunk/haskellPackages.hnix.x86_64-linux#tabs-status)
+[![Repology page](https://img.shields.io/badge/Repology-page-%23005500)](https://repology.org/project/haskell:hnix/versions)
+
+
 # hnix
 
-| [![Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/haskell-nix/Lobby)                                                                                  | CI                                                                                                                                                                                                                                         |
-| :---                                                                                                                                                                     |  :---                                                                                                                                                                                                                                      |
-| [![Hackage](https://img.shields.io/hackage/v/hnix?color=%235e5086&label=Latest%20release)](https://hackage.haskell.org/package/hnix)                                      | [![Hackage, Cabal, Linux](https://github.com/haskell-nix/hnix/workflows/Hackage,%20Cabal,%20Linux/badge.svg)](https://github.com/haskell-nix/hnix/actions?query=workflow%3A"Hackage%2C+Cabal%2C+Linux"+branch%3Amaster)                    |
-| [![Hackage Matrix Builder](https://img.shields.io/badge/Hackage%20Matrix-Builder-%235e5086)](https://matrix.hackage.haskell.org/package/hnix)                             | [![Nixpkgs, Linux, main](https://github.com/haskell-nix/hnix/workflows/Nixpkgs,%20Linux,%20main/badge.svg)](https://github.com/haskell-nix/hnix/actions?query=workflow%3A%22Nixpkgs%2C+Linux%2C+main%22+branch%3Amaster)                   |
-| [![Nixpkgs Hydra CI](https://img.shields.io/badge/Nixpkgs%20Hydra-CI-%234f72bb)](https://hydra.nixos.org/job/nixpkgs/trunk/haskellPackages.hnix.x86_64-linux#tabs-status) | [![Nixpkgs, Linux, additional](https://github.com/haskell-nix/hnix/workflows/Nixpkgs,%20Linux,%20additional/badge.svg)](https://github.com/haskell-nix/hnix/actions?query=workflow%3A%22Nixpkgs%2C+Linux%2C+additional%22+branch%3Amaster) |
-| [![Release dependencies](https://img.shields.io/hackage-deps/v/hnix?label=Release%20dependencies)](https://packdeps.haskellers.com/feed?needle=hnix)                      | [![Nixpkgs, macOS](https://github.com/haskell-nix/hnix/workflows/Nixpkgs,%20macOS/badge.svg)](https://github.com/haskell-nix/hnix/actions?query=workflow%3A%22Nixpkgs%2C+macOS%22+branch%3Amaster)                                         |
-| [![Repology page](https://img.shields.io/badge/Repology-page-%23005500)](https://repology.org/project/haskell:hnix/versions)                                              | |
+Parser, evaluator and type checker for the Nix language written in Haskell.
 
-Haskell parser, evaluator and type checker for the Nix language.
 
-## Prerequisites
+## Contents
 
-Nix is installed and in your `$PATH`. This is so that `nix-store` can be used
-for interacting with store paths, until `hnix-store` is ready.
+<!-- TOC generates automatically, do not bother editing any further TOC text -->
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
 
+
+- [Prerequisites](#prerequisites)
+- [Getting Started](#getting-started)
+  - [Cachix prebuild binary caches](#cachix-prebuild-binary-caches)
+  - [Development using Cabal](#development-using-cabal)
+    - [Building the project](#building-the-project)
+      - [With benchmarks](#with-benchmarks)
+      - [With profiling](#with-profiling)
+      - [With full debug info](#with-full-debug-info)
+    - [Run HNix](#run-hnix)
+  - [Use of the Nix-build](#use-of-the-nix-build)
+    - [Run benchmarks](#run-benchmarks)
+    - [With profiling](#with-profiling-1)
+    - [With full debug info](#with-full-debug-info-1)
+    - [Run the result](#run-the-result)
+- [Development status loop with amazing `ghcid`](#development-status-loop-with-amazing-ghcid)
+- [Using the HNix REPL](#using-the-hnix-repl)
+- [Nix laziness](#nix-laziness)
+- [Contributing](#contributing)
+- [Evaluating Nixpkgs with HNix](#evaluating-nixpkgs-with-hnix)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+
+## Prerequisites
+Tooling is WIP, `nix-shell` and `nix-store` are still used for their purpose, so, to access them Nix is required to be installed.
+
 ## Getting Started
 
 ```
-$ git clone --recursive https://github.com/haskell-nix/hnix.git
-...
-$ cd hnix
-$ nix-shell
-$ cabal v2-configure --enable-tests
-$ cabal v2-build
-$ cabal v2-test
-# To run all of the tests, which takes up to a minute:
-$ env ALL_TESTS=yes cabal v2-test
-# To run only specific tests (see `tests/Main.hs` for a list)
-$ env NIXPKGS_TESTS=yes PRETTY_TESTS=1 cabal v2-test
-$ ./dist/build/hnix/hnix --help
+# Note: --recursive
+git clone --recursive https://github.com/haskell-nix/hnix.git
+cd hnix
 ```
 
-## Using the REPL
 
-To enter the `hnix` REPL use
+### Cachix prebuild binary caches
 
+If you opt in to use of Nix environment, please enable the official HNix Cachix binary cache:
+
+1. Go through https://cachix.org/ and set it up.
+
+2. Run: `cachix use hnix`
+
+
+### Development using Cabal
+
+Cabal [Quickstart](https://cabal.readthedocs.io/en/3.4/nix-local-build.html).
+
+1. (Optional), to enter the projects reproducible Nix environment:
 ```
-hnix --repl
+nix-shell
 ```
-
-To evaluate an expression and make it available in the REPL
-as the `input` variable use
+  
+2. Building:
+```
+cabal v2-configure
+cabal v2-build
+```
 
+3. Loading the project into `ghci` REPL:
 ```
-hnix --eval -E '(import <nixpkgs> {}).pkgs.hello' --repl
+cabal v2-repl
 ```
 
-Use the `:help` command for a list of all available REPL commands.
+4. Testing:
 
-## Building with full debug info
+* Default suite:
+```
+cabal v2-test
+```
 
-To build `hnix` for debugging, and with full tracing output and stack traces,
-use:
+* All available tests:
+```
+env ALL_TESTS=yes cabal v2-test
+```
 
+* Selected (list of tests is in `tests/Main.hs`):
 ```
-$ nix-shell
-$ cabal v2-configure --enable-tests --enable-profiling --flags=profiling --flags=tracing
-$ cabal v2-build
-$ ./dist/build/hnix/hnix -v5 --trace <args> +RTS -xc
+env NIXPKGS_TESTS=yes PRETTY_TESTS=1 cabal v2-test
 ```
 
-Note that this will run quite slowly, but will give the most information as to
-what might potentially be going wrong during parsing or evaluation.
+#### Building the project
 
-## Building with benchmarks enabled
+##### With benchmarks
 
-To build `hnix` with benchmarks enabled:
+To run benchmarks:
 
 ```
-$ nix-shell --arg doBenchmarks true
-$ cabal v2-configure --enable-tests --enable-benchmarks
-$ cabal v2-build
-$ cabal v2-bench
+cabal v2-bench
 ```
 
-## Building with profiling enabled
+##### With profiling
 
 To build `hnix` with profiling enabled:
 
 ```
-$ nix-shell
-$ cabal v2-configure --enable-tests --enable-profiling --flags=profiling
-$ cabal v2-build
-$ ./dist/build/hnix/hnix <args> +RTS -p
+cabal v2-configure --enable-tests --enable-profiling --flags=profiling
+cabal v2-run hnix -- <args> +RTS -p
 ```
 
-## Building with GHCJS
+##### With full debug info
 
-From the project root directory, run:
+To build `hnix` for debugging, with full tracing output and stack traces:
 
 ```
-$ NIX_CONF_DIR=$PWD/ghcjs nix-build ghcjs
+cabal v2-configure --enable-tests --enable-profiling --flags=profiling --flags=tracing
+cabal v2-run hnix -- -v5 --trace <args> +RTS -xc
 ```
 
-This will build an `hnix` library that can be linked to your GHCJS
-application.
+Note that this going to run quite slowly, but would give the most information as to what happens during parsing & evaluation.
 
-## Using the Cachix binary cache
 
-If you're on macOS, you can use the binary cache at Cachix to avoid building
-the specific dependencies used by hnix. Just use these commands:
+#### Run HNix
+```
+cabal v2-run hnix -- --help
+```
+(`--` is for separation between `cabal` & `hnix` args)
 
+
+### Use of the Nix-build
+
+There is a number of build options to use with `nix-build`, documentation of them is in: `./default.nix`, keys essentially pass-through the [Nixpkgs Haskell Lib API](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/lib.nix).
+
+Options can be used as:
 ```
-$ nix-env -iA cachix -f https://github.com/NixOS/nixpkgs/tarball/db557aab7b690f5e0e3348459f2e4dc8fd0d9298
-$ cachix use hnix
+nix-build \
+  --arg <option1> <argument1> \
+  --arg <option2> <argument2> \
+  --argstr <option3> "<strinTypeArg>"
 ```
 
-## How you can help
+#### Run benchmarks
 
-### Issue Tracker Backlog
+```
+nix-build \
+  --arg disableOptimization false \
+  --arg enableDeadCodeElimination true \
+  --arg doStrip true \
+  --arg doBenchmark true
+```
 
-If you're looking for a way to help out, try taking a look
-[here](https://github.com/haskell-nix/hnix/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+no%3Aassignee).
-When you find an issue that looks interesting to you, comment on the ticket to
-let others know you're working on it; look for others who might have done the
-same. You can talk with everyone live on
-[Gitter](https://gitter.im/haskell-nix/Lobby).
+#### With profiling
 
-When you're ready to submit a pull request, test it with:
+```
+nix-build \
+  --arg disableOptimization false \
+  --arg enableDeadCodeElimination true \
+  --arg enableLibraryProfiling true \
+  --arg enableExecutableProfiling true
+```
 
+#### With full debug info
+
 ```
-$ git submodule update --init --recursive
-$ nix-shell --run "LANGUAGE_TESTS=yes cabal v2-test"
+nix-build \
+  --arg disableOptimization false \
+  --arg enableDeadCodeElimination true \
+  --arg doBenchmark true \
+  --arg doStrip false \
+  --arg enableLibraryProfiling true \
+  --arg enableExecutableProfiling true
+  --arg doTracing true \
+  --arg enableDWARFDebugging true
 ```
 
-Make sure that all the tests that were passing prior to your PR are still
-passing afterwards; it's OK if no new tests are passing.
+#### Run the result
 
-### Evaluating Nixpkgs with HNix
+```
+./result/bin/hnix
+```
 
-Currently the main high-level goal is to be able to evaluate all of nixpkgs. To
-run this yourself, first build hnix with `nix-build`, then run the following
-command:
+## Development status loop with amazing [`ghcid`](https://github.com/ndmitchell/ghcid)
 
 ```
-$ ./result/bin/hnix --eval -E "import <nixpkgs> {}" --find
+ghcid --command="cabal v2-repl --repl-options=-fno-code --repl-options=-fno-break-on-exception --repl-options=-fno-break-on-error --repl-options=-v1 --repl-options=-ferror-spans --repl-options=-j"
+```
+(optional) To use projects reproducible environment, wrap `ghcid ...` command into a `nix-shell --command ' '`.
+
+For simplicity `alias` the command in your shell.
+
+
+## Using the HNix REPL
+
+Enter in:
+```
+hnix --repl
+```
+
+Evaluate an expression:
+```
+hnix --eval -E '(import <nixpkgs> {}).pkgs.hello' --repl
+```
+This also binds the evaluated expression result to the `input` variable, so that variable can be inspected.
+
+Use the `:help` command for a list of all available REPL commands.
+
+## Nix laziness
+
+Nix is a lazy language with the ability of recursion, so by default REPL and eval prints are lazy:
+
+```
+hnix \
+  --eval \
+  --expr '{ x = true; }'
+  
+{ x = "<CYCLE>"; }
+```
+
+To disable laziness add the `--strict` to commands or `:set strict` in the REPL.
+
+```
+hnix \
+  --eval \
+  # Strictly \
+  --strict \
+  --expr '{ x = true; }'
+  
+{ x = true; }
+```
+
+## Contributing
+
+1. If something in the [quests](https://github.com/haskell-nix/hnix/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+no%3Aassignee) looks interesting, look through the thread and leave a comment taking it, to let others know you're working on it.
+
+2. You are free to chat with everyone on [Gitter](https://gitter.im/haskell-nix/Lobby).
+
+3. When the pull request is ready to be submitted, to save time - please, test it with:
+
+```
+git submodule update --init --recursive
+nix-shell --run "LANGUAGE_TESTS=yes cabal v2-test"
+```
+
+Please, check that all tests that were passing prior (most probably all tests mentioned in the command) are still passing for the PR, it is faster to check that locally than through CI. It's OK if no new tests are passing.
+
+## Evaluating Nixpkgs with HNix
+
+Currently, the main high-level goal is to be able to evaluate all of Nixpkgs:
+
+```
+hnix --eval -E "import <nixpkgs> {}" --find
 ```
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
diff --git a/hnix.cabal b/hnix.cabal
--- a/hnix.cabal
+++ b/hnix.cabal
@@ -1,5 +1,5 @@
 name:           hnix
-version:        0.10.1
+version:        0.11.0
 synopsis:       Haskell implementation of the Nix language
 description:    Haskell implementation of the Nix language.
 category:       System, Data, Nix
diff --git a/main/Main.hs b/main/Main.hs
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -16,7 +16,6 @@
 import           Control.Monad.Catch
 import           Control.Monad.Free
 import           Control.Monad.IO.Class
--- import           Control.Monad.ST
 import qualified Data.HashMap.Lazy             as M
 import qualified Data.Map                      as Map
 import           Data.List                      ( sortOn )
@@ -29,7 +28,6 @@
 import qualified Nix.Eval                      as Eval
 import           Nix.Fresh.Basic
 import           Nix.Json
--- import           Nix.Lint
 import           Nix.Options.Parser
 import           Nix.Standard
 import           Nix.Thunk.Basic
@@ -61,7 +59,7 @@
         Just path ->
           mapM_ (processFile opts) =<< (lines <$> liftIO (readFile path))
         Nothing -> case filePaths opts of
-          [] -> withNixContext Nothing $ Repl.main
+          [] -> withNixContext Nothing Repl.main
           ["-"] ->
             handleResult opts Nothing
               .   parseNixTextLoc
@@ -183,10 +181,10 @@
             when report $ do
               liftIO $ putStrLn path
               when descend $ case mv of
-                Nothing -> return ()
+                Nothing -> pure ()
                 Just v  -> case v of
                   NVSet s' _ -> go (path ++ ".") s'
-                  _          -> return ()
+                  _          -> pure ()
          where
           filterEntry path k = case (path, k) of
             ("stdenv", "stdenv"          ) -> (True, True)
@@ -216,7 +214,7 @@
                 =<< renderFrames @(StdValue (StandardT (StdIdT IO)))
                       @(StdThunk (StandardT (StdIdT IO)))
                       frames
-              return Nothing
+              pure Nothing
 
   reduction path mp x = do
     eres <- Nix.withNixContext mp
@@ -234,4 +232,4 @@
       writeFile path $ show $ prettyNix (stripAnnotation expr')
     case eres of
       Left  err -> throwM err
-      Right v   -> return v
+      Right v   -> pure v
diff --git a/main/Repl.hs b/main/Repl.hs
--- a/main/Repl.hs
+++ b/main/Repl.hs
@@ -16,7 +16,6 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE TypeApplications #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 
 module Repl
   ( main
@@ -97,7 +96,7 @@
       <> ". For help type :help\n"
   finalizer = do
     liftIO $ putStrLn "Goodbye."
-    return Exit
+    pure Exit
 
   rcFile = do
     f <- liftIO $ Data.Text.IO.readFile ".hnixrc" `catch` handleMissing
@@ -108,7 +107,7 @@
       x -> cmd $ unwords x
 
   handleMissing e
-    | System.IO.Error.isDoesNotExistError e = return ""
+    | System.IO.Error.isDoesNotExistError e = pure ""
     | otherwise = throwIO e
 
   -- Replicated and slightly adjusted `optMatcher` from `System.Console.Repline`
@@ -167,10 +166,8 @@
   where
     evalText :: (MonadNix e t f m) => Text -> m (NValue t f m)
     evalText expr = case parseNixTextLoc expr of
-      Failure e -> error $ "Impossible happened: Unable to parse expression - '" ++ (Data.Text.unpack expr) ++ "' error was " ++ show e
-      Success e -> do
-        value <- evalExprLoc e
-        pure value
+      Failure e -> error $ "Impossible happened: Unable to parse expression - '" ++ Data.Text.unpack expr ++ "' error was " ++ show e
+      Success e -> do evalExprLoc e
 
 type Repl e t f m = HaskelineT (StateT (IState t f m) m)
 
@@ -194,7 +191,7 @@
   case parseExprOrBinding source of
     (Failure err, _) -> do
       liftIO $ print err
-      return Nothing
+      pure Nothing
     (Success expr, isBinding) -> do
 
       -- Type Inference ( returns Typing Environment )
@@ -210,7 +207,7 @@
       case mVal of
         Left (NixException frames) -> do
           lift $ lift $ liftIO . print =<< renderFrames @(NValue t f m) @t frames
-          return Nothing
+          pure Nothing
         Right val -> do
           -- Update the interpreter state
           when (update && isBinding) $ do
@@ -220,9 +217,9 @@
             -- If the result value is a set, update our context with it
             case val of
               NVSet xs _ -> put st { replCtx = Data.HashMap.Lazy.union xs (replCtx st) }
-              _          -> return ()
+              _          -> pure ()
 
-          return $ Just val
+          pure $ Just val
   where
     -- If parsing fails, turn the input into singleton attribute set
     -- and try again.
@@ -246,7 +243,7 @@
 cmd source = do
   mVal <- exec True (Data.Text.pack source)
   case mVal of
-    Nothing -> return ()
+    Nothing -> pure ()
     Just val -> printValue val
 
 printValue :: (MonadNix e t f m, MonadIO m)
@@ -295,7 +292,7 @@
 typeof args = do
   st <- get
   mVal <- case Data.HashMap.Lazy.lookup line (replCtx st) of
-    Just val -> return $ Just val
+    Just val -> pure $ Just val
     Nothing  -> do
       exec False line
 
@@ -403,7 +400,7 @@
                 case Data.HashMap.Lazy.lookup f m of
                   Nothing -> pure []
                   Just e ->
-                    (demand e)
+                    demand e
                     (\e' -> fmap (("." <> f) <>) <$> algebraicComplete fs e')
 
       in case val of
@@ -460,7 +457,7 @@
         <> Prettyprinter.line
         <> "Available options:"
         <> Prettyprinter.line
-        <> (renderSetOptions helpSetOptions)
+        <> renderSetOptions helpSetOptions
       )
       setConfig
   ]
diff --git a/src/Nix.hs b/src/Nix.hs
--- a/src/Nix.hs
+++ b/src/Nix.hs
@@ -119,7 +119,7 @@
     Success x   -> x
     Failure err -> errorWithoutStackTrace (show err)
 
-  eval' = (normalForm =<<) . nixEvalExpr mpath
+  eval' = normalForm <=< nixEvalExpr mpath
 
   argmap args = nvSet (M.fromList args) mempty
 
diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs
--- a/src/Nix/Builtins.hs
+++ b/src/Nix/Builtins.hs
@@ -7,7 +7,6 @@
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MonoLocalBinds #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PackageImports #-}
@@ -205,7 +204,7 @@
   , add2 Normal   "elem"             elem_
   , add2 Normal   "elemAt"           elemAt_
   , add  Normal   "exec"             exec_
-  , add0 Normal   "false"            (return $ nvConstant $ NBool False)
+  , add0 Normal   "false"            (pure $ nvConstant $ NBool False)
   , add  Normal   "fetchTarball"     fetchTarball
   , add  Normal   "fetchurl"         fetchurl
   , add2 Normal   "filter"           filter_
@@ -237,7 +236,7 @@
   , add2 TopLevel "mapAttrs"         mapAttrs_
   , add2 Normal   "match"            match_
   , add2 Normal   "mul"              mul_
-  , add0 Normal   "null"             (return $ nvConstant NNull)
+  , add0 Normal   "null"             (pure $ nvConstant NNull)
   , add  Normal   "parseDrvName"     parseDrvName
   , add2 Normal   "partition"        partition_
   , add  Normal   "pathExists"       pathExists_
@@ -252,12 +251,12 @@
   , add2 Normal   "sort"             sort_
   , add2 Normal   "split"            split_
   , add  Normal   "splitVersion"     splitVersion_
-  , add0 Normal   "storeDir"         (return $ nvStr $ principledMakeNixStringWithoutContext "/nix/store")
+  , add0 Normal   "storeDir"         (pure $ nvStr $ principledMakeNixStringWithoutContext "/nix/store")
   , add' Normal   "stringLength"     (arity1 $ Text.length . principledStringIgnoreContext)
   , add' Normal   "sub"              (arity2 ((-) @Integer))
   , add' Normal   "substring"        (substring @e @t @f @m)
   , add  Normal   "tail"             tail_
-  , add0 Normal   "true"             (return $ nvConstant $ NBool True)
+  , add0 Normal   "true"             (pure $ nvConstant $ NBool True)
   , add  TopLevel "throw"            throw_
   , add  Normal   "toJSON"           prim_toJSON
   , add2 Normal   "toFile"           toFile
@@ -307,13 +306,11 @@
 foldNixPath f z = do
   mres <- lookupVar "__includes"
   dirs <- case mres of
-    Nothing -> return []
+    Nothing -> pure []
     Just v  -> demand v $ fromValue . Deeper
   mPath <- getEnvVar "NIX_PATH"
   mDataDir <- getEnvVar "NIX_DATA_DIR"
-  dataDir <- case mDataDir of
-    Nothing -> getDataDir
-    Just dataDir -> return dataDir
+  dataDir <- maybe getDataDir pure mDataDir
   foldrM go z
     $  map (fromInclude . principledStringIgnoreContext) dirs
     ++ case mPath of
@@ -331,16 +328,17 @@
 nixPath :: MonadNix e t f m => m (NValue t f m)
 nixPath = fmap nvList $ flip foldNixPath [] $ \p mn ty rest ->
   pure
-    $ (flip nvSet mempty $ M.fromList
+    $ flip nvSet mempty ( M.fromList
         [ case ty of
           PathEntryPath -> ("path", nvPath p)
           PathEntryURI ->
             ( "uri"
-            , nvStr (hackyMakeNixStringWithoutContext (Text.pack p))
+            , nvStr $ hackyMakeNixStringWithoutContext $ Text.pack p
             )
+
         , ( "prefix"
           , nvStr
-            (hackyMakeNixStringWithoutContext $ Text.pack (fromMaybe "" mn))
+            $ hackyMakeNixStringWithoutContext $ Text.pack $ fromMaybe "" mn
           )
         ]
       )
@@ -441,10 +439,10 @@
   (_, _) -> throwError $ Division x' y'
 
 anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool
-anyM _ []       = return False
+anyM _ []       = pure False
 anyM p (x : xs) = do
   q <- p x
-  if q then return True else anyM p xs
+  if q then pure True else anyM p xs
 
 any_
   :: MonadNix e t f m
@@ -454,10 +452,10 @@
 any_ f = toValue <=< anyM fromValue <=< mapM (f `callFunc`) <=< fromValue
 
 allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
-allM _ []       = return True
+allM _ []       = pure True
 allM p (x : xs) = do
   q <- p x
-  if q then allM p xs else return False
+  if q then allM p xs else pure False
 
 all_
   :: MonadNix e t f m
@@ -484,7 +482,7 @@
 tail_ :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
 tail_ = fromValue >=> \case
   []    -> throwError $ ErrorCall "builtins.tail: empty list"
-  _ : t -> return $ nvList t
+  _ : t -> pure $ nvList t
 
 data VersionComponent
    = VersionComponent_Pre -- ^ The string "pre"
@@ -528,7 +526,7 @@
 
 splitVersion_ :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
 splitVersion_ = fromValue >=> fromStringNoContext >=> \s ->
-  return
+  pure
     $ nvList
     $ flip map (splitVersion s)
     $ nvStr
@@ -549,7 +547,7 @@
   -> m (NValue t f m)
 compareVersions_ t1 t2 = fromValue t1 >>= fromStringNoContext >>= \s1 ->
   fromValue t2 >>= fromStringNoContext >>= \s2 ->
-    return $ nvConstant $ NInt $ case compareVersions s1 s2 of
+    pure $ nvConstant $ NInt $ case compareVersions s1 s2 of
       LT -> -1
       EQ -> 0
       GT -> 1
@@ -627,7 +625,7 @@
     let s = principledStringIgnoreContext ns
     let re       = makeRegex (encodeUtf8 p) :: Regex
         haystack = encodeUtf8 s
-    return $ nvList $ splitMatches 0
+    pure $ nvList $ splitMatches 0
                                    (map elems $ matchAllText re haystack)
                                    haystack
 
@@ -928,7 +926,7 @@
           (prefix, replacement) <- find ((`Text.isPrefixOf` s) . fst)
             $ zip from nsTo
           let rest = Text.drop (Text.length prefix) s
-          return (prefix, replacement, rest)
+          pure (prefix, replacement, rest)
         finish b =
           principledMakeNixString (LazyText.toStrict $ Builder.toLazyText b)
         go orig result ctx = case lookupPrefix orig of
@@ -980,7 +978,7 @@
 intersectAttrs set1 set2 =
   fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) set1 >>= \(s1, p1) ->
     fromValue @(AttrSet (NValue t f m), AttrSet SourcePos) set2 >>= \(s2, p2) ->
-      return $ nvSet (s2 `M.intersection` s1) (p2 `M.intersection` p1)
+      pure $ nvSet (s2 `M.intersection` s1) (p2 `M.intersection` p1)
 
 functionArgs
   :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)
@@ -1089,10 +1087,10 @@
     path' <- case mres of
       Nothing -> do
         traceM "No known current directory"
-        return path
+        pure path
       Just p -> demand p $ fromValue >=> \(Path p') -> do
         traceM $ "Current file being evaluated is: " ++ show p'
-        return $ takeDirectory p' </> path
+        pure $ takeDirectory p' </> path
     clearScopes @(NValue t f m)
       $ withNixContext (Just path')
       $ pushScope s
@@ -1101,9 +1099,7 @@
 getEnv_ :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
 getEnv_ = fromValue >=> fromStringNoContext >=> \s -> do
   mres <- getEnvVar (Text.unpack s)
-  toValue $ principledMakeNixStringWithoutContext $ case mres of
-    Nothing -> ""
-    Just v  -> Text.pack v
+  toValue $ principledMakeNixStringWithoutContext $ maybe "" Text.pack mres
 
 sort_
   :: MonadNix e t f m
@@ -1379,7 +1375,7 @@
 fetchurl
   :: forall e t f m . MonadNix e t f m => NValue t f m -> m (NValue t f m)
 fetchurl v = demand v $ \case
-  NVSet s _ -> attrsetGet "url" s >>= demand ?? (go (M.lookup "sha256" s))
+  NVSet s _ -> attrsetGet "url" s >>= demand ?? go (M.lookup "sha256" s)
   v@NVStr{} -> go Nothing v
   v ->
     throwError
@@ -1421,7 +1417,7 @@
 currentSystem = do
   os   <- getCurrentSystemOS
   arch <- getCurrentSystemArch
-  return $ nvStr $ principledMakeNixStringWithoutContext (arch <> "-" <> os)
+  pure $ nvStr $ principledMakeNixStringWithoutContext (arch <> "-" <> os)
 
 currentTime_ :: MonadNix e t f m => m (NValue t f m)
 currentTime_ = do
@@ -1441,7 +1437,7 @@
     let context =
           getNixLikeContext $ toNixLikeContext $ principledGetContext ns
     valued :: M.HashMap Text (NValue t f m) <- sequenceA $ M.map toValue context
-    pure $ flip nvSet M.empty $ valued
+    pure $ nvSet valued M.empty
   x ->
     throwError $ ErrorCall $ "Invalid type for builtins.getContext: " ++ show x
 
@@ -1456,12 +1452,12 @@
     newContextValues <- forM attrs $ \attr -> demand attr $ \case
       NVSet attrs _ -> do
         -- TODO: Fail for unexpected keys.
-        path <- maybe (return False) (demand ?? fromValue)
+        path <- maybe (pure False) (demand ?? fromValue)
           $ M.lookup "path" attrs
-        allOutputs <- maybe (return False) (demand ?? fromValue)
+        allOutputs <- maybe (pure False) (demand ?? fromValue)
           $ M.lookup "allOutputs" attrs
         outputs <- case M.lookup "outputs" attrs of
-          Nothing -> return []
+          Nothing -> pure []
           Just os -> demand os $ \case
             NVList vs ->
               forM vs $ fmap principledStringIgnoreContext . fromValue
@@ -1470,7 +1466,7 @@
                 $ ErrorCall
                 $ "Invalid types for context value outputs in builtins.appendContext: "
                 ++ show x
-        return $ NixLikeContextValue path allOutputs outputs
+        pure $ NixLikeContextValue path allOutputs outputs
       x ->
         throwError
           $  ErrorCall
@@ -1506,4 +1502,4 @@
          )
       => ToBuiltin t f m (a -> b) where
   toBuiltin name f =
-    return $ nvBuiltin name (fromValue . Deeper >=> toBuiltin name . f)
+    pure $ nvBuiltin name (fromValue . Deeper >=> toBuiltin name . f)
diff --git a/src/Nix/Cache.hs b/src/Nix/Cache.hs
--- a/src/Nix/Cache.hs
+++ b/src/Nix/Cache.hs
diff --git a/src/Nix/Cited.hs b/src/Nix/Cited.hs
--- a/src/Nix/Cited.hs
+++ b/src/Nix/Cited.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -57,7 +55,7 @@
 
 instance HasCitations m v (NCited m v a) where
   citations = _provenance
-  addProvenance x (NCited p v) = (NCited (x : p) v)
+  addProvenance x (NCited p v) = NCited (x : p) v
 
 class HasCitations1 m v f where
     citations1 :: f a -> [Provenance m v]
diff --git a/src/Nix/Cited/Basic.hs b/src/Nix/Cited/Basic.hs
--- a/src/Nix/Cited/Basic.hs
+++ b/src/Nix/Cited/Basic.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
diff --git a/src/Nix/Convert.hs b/src/Nix/Convert.hs
--- a/src/Nix/Convert.hs
+++ b/src/Nix/Convert.hs
@@ -1,14 +1,11 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveFoldable #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE IncoherentInstances #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TupleSections #-}
@@ -249,7 +246,7 @@
   => FromValue (AttrSet a, AttrSet SourcePos) m
               (Deeper (NValue' t f m (NValue t f m))) where
   fromValueMay = \case
-    Deeper (NVSet' s p) -> fmap (, p) <$> sequence <$> traverse fromValueMay s
+    Deeper (NVSet' s p) -> fmap (, p) . sequence <$> traverse fromValueMay s
     _                   -> pure Nothing
   fromValue v = fromValueMay v >>= \case
     Just b -> pure b
@@ -356,21 +353,21 @@
 instance Convertible e t f m
   => ToValue NixLikeContextValue m (NValue' t f m (NValue t f m)) where
   toValue nlcv = do
-    path <- if nlcvPath nlcv then Just <$> toValue True else return Nothing
+    path <- if nlcvPath nlcv then Just <$> toValue True else pure Nothing
     allOutputs <- if nlcvAllOutputs nlcv
       then Just <$> toValue True
-      else return Nothing
+      else pure Nothing
     outputs <- do
       let outputs =
-            fmap principledMakeNixStringWithoutContext $ nlcvOutputs nlcv
+            principledMakeNixStringWithoutContext <$> nlcvOutputs nlcv
       ts :: [NValue t f m] <- traverse toValue outputs
       case ts of
-        [] -> return Nothing
+        [] -> pure Nothing
         _  -> Just <$> toValue ts
     pure $ flip nvSet' M.empty $ M.fromList $ catMaybes
-      [ (\p -> ("path", p)) <$> path
-      , (\ao -> ("allOutputs", ao)) <$> allOutputs
-      , (\os -> ("outputs", os)) <$> outputs
+      [ ("path",) <$> path
+      , ("allOutputs",) <$> allOutputs
+      , ("outputs",) <$> outputs
       ]
 
 instance Convertible e t f m => ToValue () m (NExprF (NValue t f m)) where
diff --git a/src/Nix/Effects.hs b/src/Nix/Effects.hs
--- a/src/Nix/Effects.hs
+++ b/src/Nix/Effects.hs
@@ -76,7 +76,7 @@
 \_ -> return 0
 #endif
 #else
-    \_ -> return 0
+    \_ -> pure 0
 #endif
 
 class Monad m => MonadExec m where
@@ -87,26 +87,26 @@
 
 instance MonadExec IO where
   exec' = \case
-    []            -> return $ Left $ ErrorCall "exec: missing program"
+    []            -> pure $ Left $ ErrorCall "exec: missing program"
     (prog : args) -> do
       (exitCode, out, _) <- liftIO $ readProcessWithExitCode prog args ""
       let t    = T.strip (T.pack out)
       let emsg = "program[" ++ prog ++ "] args=" ++ show args
       case exitCode of
         ExitSuccess -> if T.null t
-          then return $ Left $ ErrorCall $ "exec has no output :" ++ emsg
+          then pure $ Left $ ErrorCall $ "exec has no output :" ++ emsg
           else case parseNixTextLoc t of
             Failure err ->
-              return
+              pure
                 $  Left
                 $  ErrorCall
                 $  "Error parsing output of exec: "
                 ++ show err
                 ++ " "
                 ++ emsg
-            Success v -> return $ Right v
+            Success v -> pure $ Right v
         err ->
-          return
+          pure
             $  Left
             $  ErrorCall
             $  "exec  failed: "
@@ -129,14 +129,14 @@
     case exitCode of
       ExitSuccess -> case parseNixTextLoc (T.pack out) of
         Failure e ->
-          return
+          pure
             $  Left
             $  ErrorCall
             $  "Error parsing output of nix-instantiate: "
             ++ show e
-        Success v -> return $ Right v
+        Success v -> pure $ Right v
       status ->
-        return
+        pure
           $  Left
           $  ErrorCall
           $  "nix-instantiate failed: "
@@ -161,10 +161,10 @@
 instance MonadEnv IO where
   getEnvVar            = lookupEnv
 
-  getCurrentSystemOS   = return $ T.pack System.Info.os
+  getCurrentSystemOS   = pure $ T.pack System.Info.os
 
--- Invert the conversion done by GHC_CONVERT_CPU in GHC's aclocal.m4
-  getCurrentSystemArch = return $ T.pack $ case System.Info.arch of
+  -- Invert the conversion done by GHC_CONVERT_CPU in GHC's aclocal.m4
+  getCurrentSystemArch = pure $ T.pack $ case System.Info.arch of
     "i386" -> "i686"
     arch   -> arch
 
@@ -194,7 +194,7 @@
     let status = statusCode (responseStatus response)
     if status /= 200
       then
-        return
+        pure
         $  Left
         $  ErrorCall
         $  "fail, got "
@@ -203,7 +203,7 @@
         ++ urlstr
       else -- do
         -- let bstr = responseBody response
-        return
+        pure
         $  Left
         $  ErrorCall
         $  "success in downloading but hnix-store is not yet ready; url = "
@@ -239,23 +239,23 @@
     case exitCode of
       ExitSuccess -> do
         let dropTrailingLinefeed p = take (length p - 1) p
-        return $ Right $ StorePath $ dropTrailingLinefeed out
+        pure $ Right $ StorePath $ dropTrailingLinefeed out
       _ ->
-        return
+        pure
           $  Left
           $  ErrorCall
           $  "addPath: failed: nix-store --add "
           ++ show path
 
---TODO: Use a temp directory so we don't overwrite anything important
+  --TODO: Use a temp directory so we don't overwrite anything important
   toFile_' filepath content = do
     writeFile filepath content
     storepath <- addPath' filepath
     S.removeFile filepath
-    return storepath
+    pure storepath
 
 addPath :: (Framed e m, MonadStore m) => FilePath -> m StorePath
-addPath p = either throwError return =<< addPath' p
+addPath p = either throwError pure =<< addPath' p
 
 toFile_ :: (Framed e m, MonadStore m) => FilePath -> String -> m StorePath
-toFile_ p contents = either throwError return =<< toFile_' p contents
+toFile_ p contents = either throwError pure =<< toFile_' p contents
diff --git a/src/Nix/Effects/Basic.hs b/src/Nix/Effects/Basic.hs
--- a/src/Nix/Effects/Basic.hs
+++ b/src/Nix/Effects/Basic.hs
@@ -63,7 +63,7 @@
         case mres of
           Nothing -> getCurrentDirectory
           Just v  -> demand v $ \case
-            NVPath s -> return $ takeDirectory s
+            NVPath s -> pure $ takeDirectory s
             v ->
               throwError
                 $  ErrorCall
@@ -76,7 +76,7 @@
 
 expandHomePath :: MonadFile m => FilePath -> m FilePath
 expandHomePath ('~' : xs) = flip (++) xs <$> getHomeDirectory
-expandHomePath p          = return p
+expandHomePath p          = pure p
 
 -- | Incorrectly normalize paths by rewriting patterns like @a/b/..@ to @a@.
 --   This is incorrect on POSIX systems, because if @b@ is a symlink, its
@@ -115,9 +115,9 @@
     exists <- doesDirectoryExist path
     path'  <- if exists
       then makeAbsolutePath @t @f $ path </> "default.nix"
-      else return path
+      else pure path
     exists <- doesFileExist path'
-    return $ if exists then Just path' else Nothing
+    pure $ if exists then Just path' else Nothing
 
 findPathBy
   :: forall e t f m
@@ -136,7 +136,7 @@
         ++ name
         ++ "' was not found in the Nix search path"
         ++ " (add it's using $NIX_PATH or -I)"
-    Just path -> return path
+    Just path -> pure path
  where
   go :: Maybe FilePath -> NValue t f m -> m (Maybe FilePath)
   go p@(Just _) _ = pure p
@@ -158,7 +158,7 @@
   tryPath p _ = finder $ p <///> name
 
   resolvePath s = case M.lookup "path" s of
-    Just t  -> return t
+    Just t  -> pure t
     Nothing -> case M.lookup "uri" s of
       Just ut -> defer $ fetchTarball ut
       Nothing ->
@@ -232,7 +232,7 @@
   path path = do
     path   <- makeAbsolutePath @t @f path
     exists <- doesPathExist path
-    return $ if exists then Just path else Nothing
+    pure $ if exists then Just path else Nothing
 
 defaultImportPath
   :: (MonadNix e t f m, MonadState (HashMap FilePath NExprLoc) m)
@@ -273,7 +273,7 @@
   nixInstantiateExpr $ "derivationStrict " ++ show (prettyNValue v')
  where
   mapMaybeM :: (a -> m (Maybe b)) -> [a] -> m [b]
-  mapMaybeM op = foldr f (return [])
+  mapMaybeM op = foldr f (pure [])
     where f x xs = op x >>= (<$> xs) . (++) . maybeToList
 
   handleEntry :: Bool -> (Text, NValue t f m) -> m (Maybe (Text, NValue t f m))
diff --git a/src/Nix/Eval.hs b/src/Nix/Eval.hs
--- a/src/Nix/Eval.hs
+++ b/src/Nix/Eval.hs
@@ -201,7 +201,7 @@
     -> x >>= fromValue @(AttrSet v, AttrSet SourcePos) >>= \(st, sp) ->
       recurse (demand ?? pure <$> st) sp
  where
-  go = return (M.insert k val m, M.insert k pos p)
+  go = pure (M.insert k val m, M.insert k pos p)
 
   recurse st sp = attrSetAlter ks pos st sp val <&> \(st', _) ->
     ( M.insert
@@ -257,7 +257,7 @@
   go _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) =
     finalValue >>= fromValue >>= \(o', p') ->
           -- jww (2018-05-09): What to do with the key position here?
-                                              return $ map
+                                              pure $ map
       (\(k, v) -> ([k], fromMaybe pos (M.lookup k p'), demand v pure))
       (M.toList o')
 
@@ -306,7 +306,7 @@
   buildResult scope bindings = do
     (s, p) <- foldM insert (M.empty, M.empty) bindings
     res <- if recursive then loebM (encapsulate <$> s) else traverse mkThunk s
-    return (res, p)
+    pure (res, p)
    where
     mkThunk = defer . withScopes scope
 
@@ -331,7 +331,7 @@
         []     -> pure $ Right $ demand t pure
         y : ys -> demand t $ extract ?? (y :| ys)
       | otherwise -> Left . (, path) <$> toValue (s, p)
-    Nothing -> return $ Left (x, path)
+    Nothing -> pure $ Left (x, path)
 
 -- | Evaluate a component of an attribute path in a context where we are
 -- *retrieving* a value
diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs
--- a/src/Nix/Exec.hs
+++ b/src/Nix/Exec.hs
@@ -6,7 +6,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PartialTypeSignatures #-}
 {-# LANGUAGE RankNTypes #-}
@@ -14,7 +13,6 @@
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 {-# LANGUAGE UndecidableInstances #-}
 
 {-# OPTIONS_GHC -Wno-missing-signatures #-}
@@ -360,7 +358,7 @@
   NImpl -> fromValue lval >>= \l -> if l
              then rarg >>= \rval -> fromValue rval >>= boolOp rval
              else bypass True
-  _     -> rarg >>= \rval -> 
+  _     -> rarg >>= \rval ->
              demand rval $ \rval' ->
                demand lval $ \lval' ->
                  execBinaryOpForced scope span op lval' rval'
@@ -410,13 +408,13 @@
       (\rs2 -> nvStrP prov (ls `principledStringMappend` rs2))
         <$> coerceToString callFunc CopyToStore CoerceStringy rs
     (NVPath ls, NVStr rs) -> case principledGetStringNoContext rs of
-      Just rs2 -> nvPathP prov <$> makeAbsolutePath @t @f (ls `mappend` (Text.unpack rs2))
-      Nothing -> throwError $ ErrorCall $ 
+      Just rs2 -> nvPathP prov <$> makeAbsolutePath @t @f (ls `mappend` Text.unpack rs2)
+      Nothing -> throwError $ ErrorCall $
         -- data/nix/src/libexpr/eval.cc:1412
         "A string that refers to a store path cannot be appended to a path."
     (NVPath ls, NVPath rs) -> nvPathP prov <$> makeAbsolutePath @t @f (ls ++ rs)
 
-    (ls@NVSet{}, NVStr rs) -> 
+    (ls@NVSet{}, NVStr rs) ->
       (\ls2 -> nvStrP prov (ls2 `principledStringMappend` rs))
         <$> coerceToString callFunc DontCopyToStore CoerceStringy ls
     (NVStr ls, rs@NVSet{}) ->
@@ -433,7 +431,7 @@
 
  where
   prov :: Provenance m (NValue t f m)
-  prov = (Provenance scope (NBinary_ span op (Just lval) (Just rval)))
+  prov = Provenance scope (NBinary_ span op (Just lval) (Just rval))
 
   toBool = pure . nvConstantP prov . NBool
   compare :: (forall a. Ord a => a -> a -> Bool) -> m (NValue t f m)
@@ -479,7 +477,7 @@
 -- use 'throwError'.
 fromStringNoContext :: Framed e m => NixString -> m Text
 fromStringNoContext ns = case principledGetStringNoContext ns of
-  Just str -> return str
+  Just str -> pure str
   Nothing  -> throwError $ ErrorCall "expected string with no context"
 
 addTracing
@@ -491,7 +489,7 @@
   guard (depth < 2000)
   local succ $ do
     v'@(Compose (Ann span x)) <- sequence v
-    return $ do
+    pure $ do
       opts :: Options <- asks (view hasLens)
       let rendered = if verbose opts >= Chatty
 #ifdef MIN_VERSION_pretty_show
@@ -505,7 +503,7 @@
       putStr $ show loc
       res <- k v'
       print $ msg rendered <> " ...done"
-      return res
+      pure res
 
 evalExprLoc :: forall e t f m . MonadNix e t f m => NExprLoc -> m (NValue t f m)
 evalExprLoc expr = do
diff --git a/src/Nix/Expr/Types.hs b/src/Nix/Expr/Types.hs
--- a/src/Nix/Expr/Types.hs
+++ b/src/Nix/Expr/Types.hs
@@ -3,17 +3,13 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GADTs #-}
-{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE StandaloneDeriving #-}
@@ -80,9 +76,9 @@
 -- unfortunate orphans
 instance Hashable1 NonEmpty
 
--- | The main nix expression type. This is polymorphic so that it can be made
--- a functor, which allows us to traverse expressions and map functions over
--- them. The actual 'NExpr' type is a fixed point of this functor, defined
+-- | The main Nix expression type. As it is polimophic, has a functor,
+-- which allows to traverse expressions and map functions over them.
+-- The actual 'NExpr' type is a fixed point of this functor, defined
 -- below.
 data NExprF r
   = NConstant !NAtom
@@ -367,11 +363,6 @@
   hashWithSalt salt (SourcePos f l c) =
     salt `hashWithSalt` f `hashWithSalt` l `hashWithSalt` c
 
-instance Generic1 NKeyName where
-  type Rep1 NKeyName = NKeyName
-  from1 = id
-  to1   = id
-
 instance NFData1 NKeyName where
   liftRnf _ (StaticKey  !_            ) = ()
   liftRnf _ (DynamicKey (Plain !_)    ) = ()
@@ -387,7 +378,7 @@
   liftEq _  (StaticKey  a) (StaticKey  b) = a == b
   liftEq _  _              _              = False
 
--- | @since UNRELEASED
+-- | @since 0.10.1
 instance Ord1 NKeyName where
   liftCompare cmp (DynamicKey a) (DynamicKey b) = liftCompare2 (liftCompare cmp) cmp a b
   liftCompare _   (DynamicKey _) (StaticKey _)  = LT
@@ -605,7 +596,7 @@
       j : js -> do
         NamedVar ns v _p <- xs
         guard $ (j : js) == (NE.toList ns ^.. traverse . _StaticKey)
-        return (v, rest)
+        pure (v, rest)
 
 ekey _ _ f e = fromMaybe e <$> f Nothing
 
diff --git a/src/Nix/Expr/Types/Annotated.hs b/src/Nix/Expr/Types/Annotated.hs
--- a/src/Nix/Expr/Types/Annotated.hs
+++ b/src/Nix/Expr/Types/Annotated.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE CPP                #-}
 {-# LANGUAGE DeriveAnyClass     #-}
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFoldable     #-}
-{-# LANGUAGE DeriveFunctor      #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE DeriveTraversable  #-}
 {-# LANGUAGE FlexibleInstances  #-}
@@ -149,7 +147,7 @@
   :: NExprLoc -> Ann SrcSpan (NAttrPath NExprLoc) -> Maybe NExprLoc -> NExprLoc
 nSelectLoc e1@(AnnE s1 _) (Ann s2 ats) d = case d of
   Nothing               -> AnnE (s1 <> s2) (NSelect e1 ats Nothing)
-  Just (e2@(AnnE s3 _)) -> AnnE (s1 <> s2 <> s3) (NSelect e1 ats (Just e2))
+  Just e2@(AnnE s3 _) -> AnnE (s1 <> s2 <> s3) (NSelect e1 ats (Just e2))
   _                     -> error "nSelectLoc: unexpected"
 nSelectLoc _ _ _ = error "nSelectLoc: unexpected"
 
diff --git a/src/Nix/Json.hs b/src/Nix/Json.hs
--- a/src/Nix/Json.hs
+++ b/src/Nix/Json.hs
@@ -43,14 +43,14 @@
   NVList l ->
     A.Array
       .   V.fromList
-      <$> traverse (join . lift . flip demand (return . nvalueToJSON)) l
+      <$> traverse (join . lift . flip demand (pure . nvalueToJSON)) l
   NVSet m _ -> case HM.lookup "outPath" m of
     Nothing ->
       A.Object
-        <$> traverse (join . lift . flip demand (return . nvalueToJSON)) m
-    Just outPath -> join $ lift $ demand outPath (return . nvalueToJSON)
+        <$> traverse (join . lift . flip demand (pure . nvalueToJSON)) m
+    Just outPath -> join $ lift $ demand outPath (pure . nvalueToJSON)
   NVPath p -> do
     fp <- lift $ unStorePath <$> addPath p
     addSingletonStringContext $ StringContext (Text.pack fp) DirectPath
-    return $ A.toJSON fp
+    pure $ A.toJSON fp
   v -> lift $ throwError $ CoercionToJson v
diff --git a/src/Nix/Lint.hs b/src/Nix/Lint.hs
--- a/src/Nix/Lint.hs
+++ b/src/Nix/Lint.hs
@@ -1,17 +1,13 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE TypeApplications #-}
@@ -134,30 +130,30 @@
 
 renderSymbolic :: MonadLint e m => Symbolic m -> m String
 renderSymbolic = unpackSymbolic >=> \case
-  NAny     -> return "<any>"
+  NAny     -> pure "<any>"
   NMany xs -> fmap (intercalate ", ") $ forM xs $ \case
     TConstant ys -> fmap (intercalate ", ") $ forM ys $ \case
-      TInt   -> return "int"
-      TFloat -> return "float"
-      TBool  -> return "bool"
-      TNull  -> return "null"
-    TStr    -> return "string"
+      TInt   -> pure "int"
+      TFloat -> pure "float"
+      TBool  -> pure "bool"
+      TNull  -> pure "null"
+    TStr    -> pure "string"
     TList r -> do
       x <- demand r renderSymbolic
-      return $ "[" ++ x ++ "]"
-    TSet Nothing  -> return "<any set>"
+      pure $ "[" ++ x ++ "]"
+    TSet Nothing  -> pure "<any set>"
     TSet (Just s) -> do
       x <- traverse (`demand` renderSymbolic) s
-      return $ "{" ++ show x ++ "}"
+      pure $ "{" ++ show x ++ "}"
     f@(TClosure p) -> do
       (args, sym) <- do
         f' <- mkSymbolic [f]
         lintApp (NAbs (void p) ()) f' everyPossible
       args' <- traverse renderSymbolic args
       sym'  <- renderSymbolic sym
-      return $ "(" ++ show args' ++ " -> " ++ sym' ++ ")"
-    TPath          -> return "path"
-    TBuiltin _n _f -> return "<builtin function>"
+      pure $ "(" ++ show args' ++ " -> " ++ sym' ++ ")"
+    TPath          -> pure "path"
+    TBuiltin _n _f -> pure "<builtin function>"
 
 -- This function is order and uniqueness preserving (of types).
 merge
@@ -173,8 +169,8 @@
     :: [NTypeF m (Symbolic m)]
     -> [NTypeF m (Symbolic m)]
     -> m [NTypeF m (Symbolic m)]
-  go []       _        = return []
-  go _        []       = return []
+  go []       _        = pure []
+  go _        []       = pure []
   go (x : xs) (y : ys) = case (x, y) of
     (TStr , TStr ) -> (TStr :) <$> go xs ys
     (TPath, TPath) -> (TPath :) <$> go xs ys
@@ -192,8 +188,8 @@
             >>= \j' -> demand i'
                   $ \i'' -> demand j' $ \j'' -> defer $ unify context i'' j''
         )
-        (return <$> l)
-        (return <$> r)
+        (pure <$> l)
+        (pure <$> r)
       if M.null m then go xs ys else (TSet (Just m) :) <$> go xs ys
     (TClosure{}, TClosure{}) ->
       throwError $ ErrorCall "Cannot unify functions"
@@ -236,10 +232,10 @@
   case (x', y') of
     (NAny, _) -> do
       writeVar x y'
-      return $ SV y
+      pure $ SV y
     (_, NAny) -> do
       writeVar y x'
-      return $ SV x
+      pure $ SV x
     (NMany xs, NMany ys) -> do
       m <- merge context xs ys
       if null m
@@ -325,7 +321,7 @@
   evalWith scope body = do
     s <- defer scope
     pushWeakScope ?? body $ demand s $ unpackSymbolic >=> \case
-      NMany [TSet (Just s')] -> return s'
+      NMany [TSet (Just s')] -> pure s'
       NMany [TSet Nothing] -> error "NYI: with unknown"
       _ -> throwError $ ErrorCall "scope must be a set in with statement"
 
@@ -441,7 +437,7 @@
   runFreshIdT i $ flip runReaderT (newContext opts) $ runLint action
 
 symbolicBaseEnv :: Monad m => m (Scopes m (Symbolic m))
-symbolicBaseEnv = return emptyScopes
+symbolicBaseEnv = pure emptyScopes
 
 lint :: Options -> NExprLoc -> ST s (Symbolic (Lint s))
 lint opts expr =
diff --git a/src/Nix/Normal.hs b/src/Nix/Normal.hs
--- a/src/Nix/Normal.hs
+++ b/src/Nix/Normal.hs
@@ -8,7 +8,6 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
 
 module Nix.Normal where
 
@@ -58,7 +57,7 @@
   go t k = do
     b <- seen t
     if b
-      then return $ Pure t
+      then pure $ Pure t
       else do
         i <- ask
         when (i > 2000)
@@ -70,7 +69,7 @@
     lift $ do
       res <- gets (member tid)
       unless res $ modify (insert tid)
-      return res
+      pure res
 
 normalForm
   :: ( Framed e m
diff --git a/src/Nix/Options/Parser.hs b/src/Nix/Options/Parser.hs
--- a/src/Nix/Options/Parser.hs
+++ b/src/Nix/Options/Parser.hs
@@ -28,7 +28,7 @@
 argPair = option $ str >>= \s -> case Text.findIndex (== '=') s of
   Nothing ->
     errorWithoutStackTrace "Format of --arg/--argstr in hnix is: name=expr"
-  Just i -> return $ second Text.tail $ Text.splitAt i s
+  Just i -> pure $ second Text.tail $ Text.splitAt i s
 
 nixOptions :: UTCTime -> Parser Options
 nixOptions current =
diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs
--- a/src/Nix/Parser.hs
+++ b/src/Nix/Parser.hs
@@ -53,13 +53,14 @@
 import           Control.DeepSeq
 import           Control.Monad
 import           Control.Monad.Combinators.Expr
+import           Control.Monad.State.Strict
 import           Data.Char                      ( isAlpha
                                                 , isDigit
                                                 , isSpace
                                                 )
 import           Data.Data                      ( Data(..) )
+import           Data.Fix                       ( Fix(..) )
 import           Data.Functor
-import           Data.Functor.Identity
 import           Data.HashSet                   ( HashSet )
 import qualified Data.HashSet                  as HashSet
 import           Data.List.NonEmpty             ( NonEmpty(..) )
@@ -81,7 +82,7 @@
 import           Prettyprinter                  ( Doc
                                                 , pretty
                                                 )
-import           Text.Megaparsec
+import           Text.Megaparsec         hiding ( State )
 import           Text.Megaparsec.Char
 import qualified Text.Megaparsec.Char.Lexer    as L
 
@@ -127,7 +128,7 @@
 nixSelector :: Parser (Ann SrcSpan (NAttrPath NExprLoc))
 nixSelector = annotateLocation $ do
   (x : xs) <- keyName `sepBy1` selDot
-  return $ x :| xs
+  pure $ x :| xs
 
 nixTerm :: Parser NExprLoc
 nixTerm = do
@@ -195,8 +196,11 @@
 nixNull :: Parser NExprLoc
 nixNull = annotateLocation1 (mkNullF <$ reserved "null" <?> "null")
 
+-- | 'nixTopLevelForm' returns an expression annotated with a source position,
+-- however this position doesn't include the parsed parentheses, so remove the
+-- "inner" location annotateion and annotate again, including the parentheses.
 nixParens :: Parser NExprLoc
-nixParens = parens nixToplevelForm <?> "parens"
+nixParens = annotateLocation1 (parens (stripAnn . unFix <$> nixToplevelForm) <?> "parens")
 
 nixList :: Parser NExprLoc
 nixList = annotateLocation1 (brackets (NList <$> many nixTerm) <?> "list")
@@ -291,7 +295,7 @@
   _       <- string ":"
   address <- some $ satisfy $ \x ->
     isAlpha x || isDigit x || x `elem` ("%/?:@&=+$,-_.!~*'" :: String)
-  return $ NStr $ DoubleQuoted
+  pure $ NStr $ DoubleQuoted
     [Plain $ pack $ start : protocol ++ ':' : address]
 
 nixString' :: Parser (NString NExprLoc)
@@ -361,18 +365,18 @@
   atLeft = try $ do
     name               <- identifier <* symbol "@"
     (variadic, params) <- params
-    return $ ParamSet params variadic (Just name)
+    pure $ ParamSet params variadic (Just name)
 
   -- Parameters named by an identifier on the right, or none (`{x, y} @ args`)
   atRight = do
     (variadic, params) <- params
     name               <- optional $ symbol "@" *> identifier
-    return $ ParamSet params variadic name
+    pure $ ParamSet params variadic name
 
   -- Return the parameters set.
   params = do
     (args, dotdots) <- braces getParams
-    return (dotdots, args)
+    pure (dotdots, args)
 
   -- Collects the parameters within curly braces. Returns the parameters and
   -- a boolean indicating if the parameters are variadic.
@@ -407,7 +411,7 @@
       <*> (equals *> nixToplevelForm)
       <*> pure p
       <?> "variable binding"
-  scope = parens nixToplevelForm <?> "inherit scope"
+  scope = nixParens <?> "inherit scope"
 
 keyName :: Parser (NKeyName NExprLoc)
 keyName = dynamicKey <+> staticKey where
@@ -439,7 +443,9 @@
   *> void (takeWhileP (Just "character") (\x -> x /= '\n' && x /= '\r'))
 
 whiteSpace :: Parser ()
-whiteSpace = L.space space1 lineCmnt blockCmnt
+whiteSpace = do
+  put =<< getSourcePos
+  L.space space1 lineCmnt blockCmnt
  where
   lineCmnt  = skipLineComment' "#"
   blockCmnt = L.skipBlockComment "/*" "*/"
@@ -488,10 +494,17 @@
     <$> satisfy (\x -> isAlpha x || x == '_')
     <*> takeWhileP Nothing identLetter
   guard (not (ident `HashSet.member` reservedNames))
-  return ident
+  pure ident
  where
   identLetter x = isAlpha x || isDigit x || x == '_' || x == '\'' || x == '-'
 
+-- We restrict the type of 'parens' and 'brackets' here because if they were to
+-- take a @Parser NExprLoc@ argument they would parse additional text which
+-- wouldn't be captured in the source location annotation.
+--
+-- Braces and angles in hnix don't enclose a single expression so this type
+-- restriction would not be useful.
+parens, brackets :: Parser (NExprF f) -> Parser (NExprF f)
 parens = between (symbol "(") (symbol ")")
 braces = between (symbol "{") (symbol "}")
 -- angles    = between (symbol "<") (symbol ">")
@@ -513,20 +526,24 @@
 reservedNames = HashSet.fromList
   ["let", "in", "if", "then", "else", "assert", "with", "rec", "inherit"]
 
-type Parser = ParsecT Void Text Identity
+type Parser = ParsecT Void Text (State SourcePos)
 
 data Result a = Success a | Failure (Doc Void) deriving (Show, Functor)
 
 parseFromFileEx :: MonadFile m => Parser a -> FilePath -> m (Result a)
 parseFromFileEx p path = do
   txt <- decodeUtf8 <$> readFile path
-  return $ either (Failure . pretty . errorBundlePretty) Success $ parse p
-                                                                         path
-                                                                         txt
+  pure
+    $ either (Failure . pretty . errorBundlePretty) Success
+    . flip evalState (initialPos path)
+    $ runParserT p path txt
 
 parseFromText :: Parser a -> Text -> Result a
 parseFromText p txt =
-  either (Failure . pretty . errorBundlePretty) Success $ parse p "<string>" txt
+  let file = "<string>"
+  in  either (Failure . pretty . errorBundlePretty) Success
+        . flip evalState (initialPos file)
+        $ runParserT p file txt
 
 {- Parser.Operators -}
 
@@ -546,7 +563,7 @@
 annotateLocation p = do
   begin <- getSourcePos
   res   <- p
-  end   <- getSourcePos
+  end   <- get -- The state set before the last whitespace
   pure $ Ann (SrcSpan begin end) res
 
 annotateLocation1 :: Parser (NExprF NExprLoc) -> Parser NExprLoc
@@ -564,7 +581,7 @@
 opWithLoc name op f = do
   Ann ann _ <- annotateLocation $ {- dbg (unpack name) $ -}
                                   operator name
-  return $ f (Ann ann op)
+  pure $ f (Ann ann op)
 
 binaryN name op =
   (NBinaryDef name op NAssocNone, InfixN (opWithLoc name op nBinary))
diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs
--- a/src/Nix/Pretty.hs
+++ b/src/Nix/Pretty.hs
@@ -7,7 +7,6 @@
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 {-# LANGUAGE ViewPatterns #-}
 
 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
@@ -16,7 +15,6 @@
 module Nix.Pretty where
 
 import           Control.Applicative            ( (<|>) )
-import           Control.Comonad
 import           Control.Monad.Free
 import           Data.Fix                       ( Fix(..), foldFix )
 import           Data.HashMap.Lazy              ( toList )
@@ -44,13 +42,7 @@
 import           Nix.Parser
 import           Nix.String
 import           Nix.Thunk
-#if ENABLE_TRACING
-import           Nix.Utils
-#else
-import           Nix.Utils               hiding ( (<$>) )
-#endif
 import           Nix.Value
-import           Prelude                 hiding ( (<$>) )
 import           Prettyprinter
 import           Text.Read                      ( readMaybe )
 
@@ -214,7 +206,7 @@
   go = exprFNixDoc . annotated . getCompose . fmap render
 
   render :: Maybe (NValue t f m) -> NixDoc ann
-  render Nothing = simpleExpr $ "_"
+  render Nothing = simpleExpr "_"
   render (Just (Free (reverse . citations @m -> p:_))) = go (_originExpr p)
   render _       = simpleExpr "?"
     -- render (Just (NValue (citations -> ps))) =
@@ -410,8 +402,8 @@
    where
     check v = fromMaybe
       v
-      (   (fmap (surround . show) (readMaybe v :: Maybe Int))
-      <|> (fmap (surround . show) (readMaybe v :: Maybe Float))
+      (   fmap (surround . show) (readMaybe v :: Maybe Int)
+      <|> fmap (surround . show) (readMaybe v :: Maybe Float)
       )
       where surround s = "\"" ++ s ++ "\""
   phi NVClosure'{}        = "<<lambda>>"
diff --git a/src/Nix/Reduce.hs b/src/Nix/Reduce.hs
--- a/src/Nix/Reduce.hs
+++ b/src/Nix/Reduce.hs
@@ -2,18 +2,14 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE ApplicativeDo #-}
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PartialTypeSignatures #-}
-{-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
@@ -44,11 +40,8 @@
 import           Control.Monad.Reader
 import           Control.Monad.State.Strict
 import           Data.Fix                       ( Fix(..), foldFix, foldFixM )
--- import           Data.Foldable
 import           Data.HashMap.Lazy              ( HashMap )
 import qualified Data.HashMap.Lazy             as M
--- import           Data.HashSet (HashSet)
--- import qualified Data.HashSet as S
 import           Data.IORef
 import           Data.List.NonEmpty             ( NonEmpty(..) )
 import qualified Data.List.NonEmpty            as NE
@@ -392,7 +385,7 @@
   pruneParams (Param n) = Param n
   pruneParams (ParamSet xs b n)
     | reduceSets opts = ParamSet
-      (map (second (maybe (Just nNull) Just . fmap (fromMaybe nNull))) xs)
+      (map (second (maybe (Just nNull) (Just . fromMaybe nNull))) xs)
       b
       n
     | otherwise = ParamSet (map (second (fmap (fromMaybe nNull))) xs) b n
diff --git a/src/Nix/Render.hs b/src/Nix/Render.hs
--- a/src/Nix/Render.hs
+++ b/src/Nix/Render.hs
@@ -118,12 +118,12 @@
       .   T.decodeUtf8
       <$> readFile path
     let
-      nums    = map (show . fst) $ zip [beg' ..] ls
+      nums    = zipWith (curry (show . fst)) [beg' ..] ls
       longest = maximum (map length nums)
       nums'   = flip map nums $ \n -> replicate (longest - length n) ' ' ++ n
       pad n | read n == begLine = "==> " ++ n
             | otherwise         = "    " ++ n
       ls' = zipWith (<+>)
                     (map (pretty . pad) nums')
-                    (zipWith (<+>) (repeat "| ") ls)
+                    (map ((<+>) "| ") ls)
     pure $ vsep $ ls' ++ [msg]
diff --git a/src/Nix/Render/Frame.hs b/src/Nix/Render/Frame.hs
--- a/src/Nix/Render/Frame.hs
+++ b/src/Nix/Render/Frame.hs
@@ -9,7 +9,6 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
 
 module Nix.Render.Frame where
 
diff --git a/src/Nix/Scope.hs b/src/Nix/Scope.hs
--- a/src/Nix/Scope.hs
+++ b/src/Nix/Scope.hs
@@ -1,13 +1,10 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 
@@ -81,17 +78,17 @@
 lookupVarReader k = do
   mres <- asks (scopeLookup k . lexicalScopes @m . view hasLens)
   case mres of
-    Just sym -> return $ Just sym
+    Just sym -> pure $ Just sym
     Nothing  -> do
       ws <- asks (dynamicScopes . view hasLens)
       foldr
         (\x rest -> do
           mres' <- M.lookup k . getScope <$> x
           case mres' of
-            Just sym -> return $ Just sym
+            Just sym -> pure $ Just sym
             Nothing  -> rest
         )
-        (return Nothing)
+        (pure Nothing)
         ws
 
 withScopes :: Scoped a m => Scopes m a -> m r -> m r
diff --git a/src/Nix/String.hs b/src/Nix/String.hs
--- a/src/Nix/String.hs
+++ b/src/Nix/String.hs
@@ -224,7 +224,7 @@
 
 -- | Get the contents of a 'NixString' and write its context into the resulting set.
 extractNixString :: Monad m => NixString -> WithStringContextT m Text
-extractNixString (NixString s c) = WithStringContextT $ tell c >> return s
+extractNixString (NixString s c) = WithStringContextT $ tell c >> pure s
 
 -- | Run an action producing a string with a context and put those into a 'NixString'.
 runWithStringContextT :: Monad m => WithStringContextT m Text -> m NixString
diff --git a/src/Nix/TH.hs b/src/Nix/TH.hs
--- a/src/Nix/TH.hs
+++ b/src/Nix/TH.hs
@@ -2,7 +2,6 @@
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 
 {-# OPTIONS_GHC -Wno-missing-fields #-}
 
@@ -18,6 +17,7 @@
 import           Data.List.NonEmpty             ( NonEmpty(..) )
 import           Data.Maybe                     ( mapMaybe )
 import           Language.Haskell.TH
+import           Language.Haskell.TH.Syntax     ( liftString )
 import           Language.Haskell.TH.Quote
 import           Nix.Atoms
 import           Nix.Expr
@@ -27,14 +27,19 @@
 quoteExprExp s = do
   expr <- case parseNixText (Text.pack s) of
     Failure err -> fail $ show err
-    Success e   -> return e
-  dataToExpQ (const Nothing `extQ` metaExp (freeVars expr)) expr
+    Success e   -> pure e
+  dataToExpQ
+    (const Nothing `extQ` metaExp (freeVars expr) `extQ` (Just . liftText))
+    expr
+ where
+  liftText :: Text.Text -> Q Exp
+  liftText txt = AppE (VarE 'Text.pack) <$> liftString (Text.unpack txt)
 
 quoteExprPat :: String -> PatQ
 quoteExprPat s = do
   expr <- case parseNixText (Text.pack s) of
     Failure err -> fail $ show err
-    Success e   -> return e
+    Success e   -> pure e
   dataToPatQ (const Nothing `extQ` metaPat (freeVars expr)) expr
 
 freeVars :: NExpr -> Set VarName
diff --git a/src/Nix/Thunk.hs b/src/Nix/Thunk.hs
--- a/src/Nix/Thunk.hs
+++ b/src/Nix/Thunk.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE DefaultSignatures #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
 
diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs
--- a/src/Nix/Thunk/Basic.hs
+++ b/src/Nix/Thunk/Basic.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -60,7 +58,7 @@
         Computed v -> k v
         _          -> n
       _ <- atomicModifyVar active (False, )
-      return res
+      pure res
 
 forceThunk
   :: forall m v a
@@ -89,7 +87,7 @@
 forceEffects (Thunk _ active ref) k = do
   nowActive <- atomicModifyVar active (True, )
   if nowActive
-    then return $ error "Loop detected"
+    then pure $ error "Loop detected"
     else do
       eres <- readVar ref
       case eres of
@@ -105,4 +103,4 @@
   _ <- atomicModifyVar ref $ \x -> case x of
     Computed _ -> (x, x)
     Deferred d -> (Deferred (k d), x)
-  return t
+  pure t
diff --git a/src/Nix/Type/Infer.hs b/src/Nix/Type/Infer.hs
--- a/src/Nix/Type/Infer.hs
+++ b/src/Nix/Type/Infer.hs
@@ -61,8 +61,6 @@
 import           Nix.Fresh
 import           Nix.String
 import           Nix.Scope
--- import           Nix.Thunk
--- import           Nix.Thunk.Basic
 import qualified Nix.Type.Assumption           as As
 import           Nix.Type.Env
 import qualified Nix.Type.Env                  as Env
diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs
--- a/src/Nix/Utils.hs
+++ b/src/Nix/Utils.hs
@@ -2,7 +2,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -14,14 +13,14 @@
 module Nix.Utils (module Nix.Utils, module X) where
 
 import           Control.Arrow                  ( (&&&) )
-import           Control.Monad
-import           Control.Monad.Fix
-import           Control.Monad.Free
+import           Control.Monad                  ( (<=<) )
+import           Control.Monad.Fix              ( MonadFix(..) )
+import           Control.Monad.Free             ( Free(..) )
 import           Control.Monad.Trans.Control    ( MonadTransControl(..) )
 import qualified Data.Aeson                    as A
 import qualified Data.Aeson.Encoding           as A
-import           Data.Fix
-import           Data.Hashable
+import           Data.Fix                       ( Fix(..) )
+import           Data.Hashable                  ( Hashable )
 import           Data.HashMap.Lazy              ( HashMap )
 import qualified Data.HashMap.Lazy             as M
 import           Data.List                      ( sortOn )
@@ -33,7 +32,7 @@
 import           Lens.Family2.Stock             ( _1
                                                 , _2
                                                 )
-import           Lens.Family2.TH
+import           Lens.Family2.TH                ( makeLensesBy )
 
 #if ENABLE_TRACING
 import           Debug.Trace as X
@@ -46,7 +45,7 @@
 trace :: String -> a -> a
 trace = const id
 traceM :: Monad m => String -> m ()
-traceM = const (return ())
+traceM = const (pure ())
 #endif
 
 $(makeLensesBy (\n -> Just ("_" ++ n)) ''Fix)
@@ -55,13 +54,13 @@
 
 type AttrSet = HashMap Text
 
--- | An f-algebra defines how to reduced the fixed-point of a functor to a
+-- | F-algebra defines how to reduce the fixed-point of a functor to a
 --   value.
 type Alg f a = f a -> a
 
 type AlgM f m a = f a -> m a
 
--- | An "transform" here is a modification of a catamorphism.
+-- | "Transform" here means a modification of a catamorphism.
 type Transform f a = (Fix f -> a) -> Fix f -> a
 
 (<&>) :: Functor f => f a -> (a -> c) -> f c
@@ -96,7 +95,7 @@
   => ((a -> m (StT u b)) -> m (StT u b))
   -> (a -> u m b)
   -> u m b
-lifted f k = liftWith (\run -> f (run . k)) >>= restoreT . return
+lifted f k = liftWith (\run -> f (run . k)) >>= restoreT . pure
 
 freeToFix :: Functor f => (a -> Fix f) -> Free f a -> Fix f
 freeToFix f = go
diff --git a/src/Nix/Utils/Fix1.hs b/src/Nix/Utils/Fix1.hs
--- a/src/Nix/Utils/Fix1.hs
+++ b/src/Nix/Utils/Fix1.hs
@@ -5,21 +5,22 @@
 {-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 
 module Nix.Utils.Fix1 where
 
-import           Control.Applicative
-import           Control.Monad
+import           Control.Applicative            ( Alternative )
 #if !MIN_VERSION_base(4,13,0)
 import           Control.Monad.Fail
 #endif
-import           Control.Monad.Fix
-import           Control.Monad.IO.Class
-import           Control.Monad.Catch
-import           Control.Monad.Reader
-import           Control.Monad.State
+import           Control.Monad                  ( MonadPlus )
+import           Control.Monad.Fix              ( MonadFix )
+import           Control.Monad.IO.Class         ( MonadIO )
+import           Control.Monad.Catch            ( MonadCatch
+                                                , MonadMask
+                                                , MonadThrow )
+import           Control.Monad.Reader           ( MonadReader )
+import           Control.Monad.State            ( MonadState )
 
 -- | The fixpoint combinator, courtesy of Gregory Malecha.
 --   https://gist.github.com/gmalecha/ceb3778b9fdaa4374976e325ac8feced
diff --git a/src/Nix/Value.hs b/src/Nix/Value.hs
--- a/src/Nix/Value.hs
+++ b/src/Nix/Value.hs
@@ -3,8 +3,6 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -12,7 +10,6 @@
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE RankNTypes #-}
@@ -54,7 +51,7 @@
 import           Nix.Thunk
 import           Nix.Utils
 
--- | An 'NValue' is the most reduced form of an 'NExpr' after evaluation is
+-- | 'NValue' is the most reduced form of a 'NExpr' after evaluation is
 --   completed. 's' is related to the type of errors that might occur during
 --   construction or use of a value.
 data NValueF p m r
@@ -83,8 +80,7 @@
       --   result.
     deriving (Generic, Typeable, Functor)
 
--- | This 'Foldable' instance only folds what the value actually is known to
---   contain at time of fold.
+-- | Folds what the value is known to contain at time of fold.
 instance Foldable (NValueF p m) where
   foldMap f = \case
     NVConstantF _  -> mempty
@@ -376,7 +372,7 @@
   => String
   -> (NValue t f m -> m (NValue t f m))
   -> m (NValue t f m)
-builtin name f = return $ nvBuiltin name $ \a -> f a
+builtin name f = pure $ nvBuiltin name $ \a -> f a
 
 builtin2
   :: (MonadThunk t m (NValue t f m), MonadDataContext f m)
@@ -447,7 +443,7 @@
               => NValue t f m -> m String
 showValueType (Pure t) = force t showValueType
 showValueType (Free (NValue (extract -> v))) =
-  pure $ describeValue $ valueType $ v
+  pure $ describeValue $ valueType v
 
 data ValueFrame t f m
     = ForcingThunk t
diff --git a/src/Nix/Value/Equal.hs b/src/Nix/Value/Equal.hs
--- a/src/Nix/Value/Equal.hs
+++ b/src/Nix/Value/Equal.hs
@@ -3,8 +3,6 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -12,7 +10,6 @@
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE RankNTypes #-}
@@ -74,7 +71,7 @@
   -> m Bool
 alignEqM eq fa fb = fmap (either (const False) (const True)) $ runExceptT $ do
   pairs <- forM (Data.Align.align fa fb) $ \case
-    These a b -> return (a, b)
+    These a b -> pure (a, b)
     _         -> throwE ()
   forM_ pairs $ \(a, b) -> guard =<< lift (eq a b)
 
@@ -174,7 +171,7 @@
 thunkEqM :: (MonadThunk t m (NValue t f m), Comonad f) => t -> t -> m Bool
 thunkEqM lt rt = force lt $ \lv -> force rt $ \rv ->
   let unsafePtrEq = case (lt, rt) of
-        (thunkId -> lid, thunkId -> rid) | lid == rid -> return True
+        (thunkId -> lid, thunkId -> rid) | lid == rid -> pure True
         _ -> valueEqM lv rv
   in  case (lv, rv) of
         (NVClosure _ _, NVClosure _ _) -> unsafePtrEq
diff --git a/src/Nix/XML.hs b/src/Nix/XML.hs
--- a/src/Nix/XML.hs
+++ b/src/Nix/XML.hs
@@ -18,7 +18,7 @@
 toXML :: forall t f m . MonadDataContext f m => NValue t f m -> NixString
 toXML = runWithStringContext . fmap pp . iterNValue (\_ _ -> cyc) phi
  where
-  cyc = return $ mkElem "string" "value" "<CYCLE>"
+  cyc = pure $ mkElem "string" "value" "<CYCLE>"
 
   pp =
     ("<?xml version='1.0' encoding='utf-8'?>\n" <>)
@@ -30,18 +30,18 @@
   phi :: NValue' t f m (WithStringContext Element) -> WithStringContext Element
   phi = \case
     NVConstant' a -> case a of
-      NURI   t -> return $ mkElem "string" "value" (Text.unpack t)
-      NInt   n -> return $ mkElem "int" "value" (show n)
-      NFloat f -> return $ mkElem "float" "value" (show f)
-      NBool  b -> return $ mkElem "bool" "value" (if b then "true" else "false")
-      NNull    -> return $ Element (unqual "null") [] [] Nothing
+      NURI   t -> pure $ mkElem "string" "value" (Text.unpack t)
+      NInt   n -> pure $ mkElem "int" "value" (show n)
+      NFloat f -> pure $ mkElem "float" "value" (show f)
+      NBool  b -> pure $ mkElem "bool" "value" (if b then "true" else "false")
+      NNull    -> pure $ Element (unqual "null") [] [] Nothing
 
     NVStr' str ->
       mkElem "string" "value" . Text.unpack <$> extractNixString str
     NVList' l -> sequence l
-      >>= \els -> return $ Element (unqual "list") [] (Elem <$> els) Nothing
+      >>= \els -> pure $ Element (unqual "list") [] (Elem <$> els) Nothing
 
-    NVSet' s _ -> sequence s >>= \kvs -> return $ Element
+    NVSet' s _ -> sequence s >>= \kvs -> pure $ Element
       (unqual "attrs")
       []
       (map
@@ -57,9 +57,9 @@
       Nothing
 
     NVClosure' p _ ->
-      return $ Element (unqual "function") [] (paramsXML p) Nothing
-    NVPath' fp        -> return $ mkElem "path" "value" fp
-    NVBuiltin' name _ -> return $ mkElem "function" "name" name
+      pure $ Element (unqual "function") [] (paramsXML p) Nothing
+    NVPath' fp        -> pure $ mkElem "path" "value" fp
+    NVBuiltin' name _ -> pure $ mkElem "function" "name" name
     _                 -> error "Pattern synonyms mask coverage"
 
 mkElem :: String -> String -> String -> Element
diff --git a/tests/EvalTests.hs b/tests/EvalTests.hs
--- a/tests/EvalTests.hs
+++ b/tests/EvalTests.hs
@@ -13,7 +13,6 @@
 import           Control.Monad (when, unless)
 import           Control.Monad.Catch
 import           Control.Monad.IO.Class
--- import qualified Data.HashMap.Lazy as M
 import           Data.List ((\\))
 import           Data.Maybe (isJust)
 import qualified Data.Set as S
@@ -441,7 +440,7 @@
     let unmaskedFiles = filter ((==".nix") . takeExtension) td
     let files = unmaskedFiles \\ maskedFiles
 
-    return $ testGroup "Eval comparison tests" $ map (mkTestCase testDir) files
+    pure $ testGroup "Eval comparison tests" $ map (mkTestCase testDir) files
   where
     mkTestCase td f = testCase f $ assertEvalFileMatchesNix (td </> f)
 
@@ -454,7 +453,7 @@
         expectedNF <- normalForm =<< nixEvalExprLoc Nothing expected
         actualNF <- normalForm =<< nixEvalExprLoc Nothing actual
         eq <- valueEqM expectedNF actualNF
-        return (eq, expectedNF, actualNF)
+        pure (eq, expectedNF, actualNF)
     let message =
                 "Inequal normal forms:\n"
             <>  "Expected: " <> printNix expectedNF <> "\n"
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -74,7 +74,7 @@
             -- Parse and deepseq the resulting expression tree, to ensure the
             -- parser is fully executed.
             _ <- consider file (parseNixFileLoc file) $ Exc.evaluate . force
-            return ()
+            pure ()
     v -> error $ "Unexpected parse from default.nix: " ++ show v
  where
   getExpr   k m = let Just (Just r) = lookup k m in r
diff --git a/tests/NixLanguageTests.hs b/tests/NixLanguageTests.hs
--- a/tests/NixLanguageTests.hs
+++ b/tests/NixLanguageTests.hs
@@ -86,7 +86,7 @@
   let testsByName = groupBy (takeFileName . dropExtensions) testFiles
   let testsByType = groupBy testType (Map.toList testsByName)
   let testGroups  = map mkTestGroup (Map.toList testsByType)
-  return $ localOption (mkTimeout 2000000) $ testGroup
+  pure $ localOption (mkTimeout 2000000) $ testGroup
     "Nix (upstream) language tests"
     testGroups
  where
@@ -105,7 +105,7 @@
 
 assertParse :: Options -> FilePath -> Assertion
 assertParse _opts file = parseNixFileLoc file >>= \case
-  Success _expr -> return () -- pure $! runST $ void $ lint opts expr
+  Success _expr -> pure () -- pure $! runST $ void $ lint opts expr
   Failure err ->
     assertFailure $ "Failed to parse " ++ file ++ ":\n" ++ show err
 
@@ -121,9 +121,9 @@
             ++ file
             ++ ":\nParsed value: "
             ++ show expr
-        Failure _ -> return ()
+        Failure _ -> pure ()
       )
-    $ \(_ :: SomeException) -> return ()
+    $ \(_ :: SomeException) -> pure ()
 
 assertLangOk :: Options -> FilePath -> Assertion
 assertLangOk opts file = do
@@ -147,8 +147,8 @@
     []                 -> () <$ hnixEvalFile opts (name ++ ".nix")
     [".exp"         ]  -> assertLangOk opts name
     [".exp.xml"     ]  -> assertLangOkXml opts name
-    [".exp.disabled"]  -> return ()
-    [".exp-disabled"]  -> return ()
+    [".exp.disabled"]  -> pure ()
+    [".exp-disabled"]  -> pure ()
     [".exp", ".flags"] -> do
       liftIO $ setEnv "NIX_PATH" "lang/dir4:lang/dir5"
       flags <- Text.readFile (name ++ ".flags")
@@ -179,7 +179,7 @@
   fixup []                          = []
 
 assertEvalFail :: FilePath -> Assertion
-assertEvalFail file = catch ?? (\(_ :: SomeException) -> return ()) $ do
+assertEvalFail file = catch ?? (\(_ :: SomeException) -> pure ()) $ do
   time       <- liftIO getCurrentTime
   evalResult <- printNix <$> hnixEvalFile (defaultOptions time) file
   evalResult
diff --git a/tests/ParserTests.hs b/tests/ParserTests.hs
--- a/tests/ParserTests.hs
+++ b/tests/ParserTests.hs
@@ -383,7 +383,7 @@
 
 assertParseFail :: Text -> Assertion
 assertParseFail str = case parseNixText str of
-  Failure _ -> return ()
+  Failure _ -> pure ()
   Success r ->
       assertFailure $ "Unexpected success parsing `"
           ++ unpack str ++ ":\nParsed value: " ++ show r
diff --git a/tests/TestCommon.hs b/tests/TestCommon.hs
--- a/tests/TestCommon.hs
+++ b/tests/TestCommon.hs
@@ -58,7 +58,7 @@
   hClose h
   res <- nixEvalFile fp
   removeLink fp
-  return res
+  pure res
 
 nixEvalFile :: FilePath -> IO String
 nixEvalFile fp = readProcess "nix-instantiate" ["--eval", "--strict", fp] ""
