ghcid: must-have tool for Haskell developer

18 Aug 2016

Usually when programming in Haskell, I rely a lot on compiler. It catches many errors that are caused by inattention, which occur especially often when refactoring large portions of code. In some sense famous "it compiles, therefore it works" mantra is true (assuming that you don't have logical errors). The problem with this approach for me for a long time was that I ran compiler manually and then read its output. The output was usually quite long, and I had to read it and start fixing errors from the top, otherwise I might end up fixing wrong error. It was a tedious routine, even with a help of bash scripts and file watchers, but thanks to ghcid1, I am free from it now.

ghcid can be interpreted as "GHCi-daemon" or "GHC-with-a-bit-of-IDE". It is a rather small program which starts GHCi, imports your modules there, executes some Haskell expression in it, watches your source code and fires :reload and reevaluates expression once something is changed. It also captures warnings and errors produced by compiler, and presents them in a way where you can see the topmost ones right away, without scrolling the whole output to the top. Last but not least is that it plays really well with stack, which is de-facto a standard tool for building and testing Haskell projects nowadays.

How to use it

First, install it:

$ stack install ghcid

Now you can run it with stack exec. At this point I usually make a bash script and tune ghcid the way I need it for my application.

First of all we need to setup is the expression which will be evaluated in GHCi session. You can do it with -T flag. If you want to run something different than GHCi, you can pass the command to -c flag. By default ghcid detects whether you're using stack or just plain cabal and runs either stack repl or cabal repl respectively.

Another thing I usually turn on for my projects are -Wall -Werror compiler flags. It catches such errors as redundant imports, orphan instances, unused variables and helps you keep the codebase clean. However, when working in a REPL mode, you'd usually concentrate on the big picture and leave those warnings to be fixed later, e.g. before committing code. When -W option is passed ghcid doesn't take those errors into account and evaluate given expression anyway.

By default ghcid watches only for those source files that were loaded by GHCi. Sometimes it might not be enough. For example, now I'm working on application which has Hamlet templates in templates directory and I'd like to reload the app each time some of templates is changed. Luckily it's easy to make ghcid do so with --restart=<PATH> or --reload=<PATH> options. The first one will rebuild the project and restart the whole GHCi process while the second one will just fire :reload command to existing GHCi process whenever any of the files and directories in <PATH> is changed.

Issues and ways to improve

One thing that would be nice to have is errors highlighting. Sure they are printed in bold font now, but having line numbers and error messages in different colors would help even more. Right now it is possible to achieve by using ghcid inside terminal emulator in Neovim or Emacs.

Currently highlighting is the only thing that comes to my mind. Overall ghcid is a great development tool, and even minor bugs (usually caused by GHCi) can't really outweigh its advantages. Definitely must-have.

  1. ndmitchell/ghcid: Very low feature GHCi based IDE