Rewriting to Haskell–Making GHC More Nitpicky

Posted on April 6, 2020 by Riccardo.

Rewriting to Haskell (Series)

Rewriting to Haskell–Intro Rewriting to Haskell–Project Setup Rewriting to Haskell–Deployment Rewriting to Haskell–Automatic Formatting Rewriting to Haskell–Configuration Rewriting to Haskell–Standing on the shoulders of Rails Rewriting to Haskell–Making GHC More Nitpicky Rewriting to Haskell–Testing Rewriting to Haskell–Linting Rewriting to Haskell–Parsing Query Params Rewriting to Haskell–Parsing Query Params, Again Rewriting to Haskell–Errors

GHC by default compiles with some warnings enabled. But there’s a ton more. Thus, we decided to turn on several. Also, we have the compiler treat them as errors with -Wall. Luckily, Max Tagher did all the work for us and prepared a “Copy-Pastable List” with nice explanations for us lazy developers. Thanks Max!

This is what we threw in package.yaml:

 library:
   source-dirs: src
+  ghc-options:
+    # For details on warnings: https://downloads.haskell.org/~ghc/master/users-guide/using-warnings.html
+    # This list taken from https://medium.com/mercury-bank/enable-all-the-warnings-a0517bc081c3
+    # Enable all warnings with -Weverything, then disable the ones we don’t care about
+    - -Weverything
+    - -Werror
+    - -Wno-missing-exported-signatures # missing-exported-signatures turns off the more strict -Wmissing-signatures. See https://ghc.haskell.org/trac/ghc/ticket/14794#ticket
+    - -Wno-missing-import-lists # Requires explicit imports of _every_ function (e.g. ‘$’); too strict
+    - -Wno-missed-specialisations # When GHC can’t specialize a polymorphic function. No big deal and requires fixing underlying libraries to solve.
+    - -Wno-all-missed-specialisations # See missed-specialisations
+    - -Wno-unsafe # Don’t use Safe Haskell warnings
+    - -Wno-safe # Don’t use Safe Haskell warnings
+    - -Wno-missing-local-signatures # Warning for polymorphic local bindings; nothing wrong with those.
+    - -Wno-monomorphism-restriction # Don’t warn if the monomorphism restriction is used
   exposed-modules:

Turns out we have been disciplined enough to just need a few edits to fix the new errors. What follows is a non-comprehensive list of the changes we performed together with the warning that was triggered.

-Wmissing-import-lists:

-module Api.Search where
+module Api.Search
+  ( SearchAPI,
+    getResults,
+  )
+where

-Wimplicit-prelude:

 import Servant ((:>), Get, Handler, JSON, QueryParam)
+import Prelude

-Wincomplete-patterns:

 instance FromJSON Configuration where
   parseJSON (Object x) = do
     -- ...
+  parseJSON _ = fail "was expecting an object"

-Wmissing-exported-signatures:

+joinComments :: Query
 joinComments = "LEFT JOIN comments ON posts.id = comments.post_id"

+textOrTitle :: Query
 textOrTitle = "(posts.text ILIKE ? OR posts.title ILIKE ?)"

Some warnings can be annoying or even unneeded depending on the use-case, your mileage may vary. Feel free to treat this as a starting point and tweak the options down the line.


I need your help to make the blog awesome. Here's a survey. Since there are no required questions, you decide how much time to spend on it.

Support my work by tweeting this article! 🙏