Haskell development with Nix

June 05, 2015

The project

This is a barebones Warp application that responds to all requests with an HTTP 200 and a Hello, world!.

Main.hs:

{-# LANGUAGE OverloadedStrings #-}

import Network.Wai (Application, responseLBS)
import Network.Wai.Handler.Warp (run)
import Network.HTTP.Types (status200)
import Network.HTTP.Types.Header (hContentType)

main :: IO ()
main = run 3000 app

app :: Application
app req respond = respond $
  responseLBS status200 [(hContentType, "text/html")] "<h1>Hello, world!</h1>"

The simple way

Let Nix do the complex work of dependency resolution and management.

Create a default.nix file that extends Nix's cabal definition:

default.nix:

{ haskellPackages ? (import <nixpkgs> {}).haskellPackages }:

haskellPackages.cabal.mkDerivation (self: {
  pname = "hello-warp";
  version = "0.1.0.0";
  src = ./.;
  buildDepends = [
    # Project dependencies go here
  ];
  buildTools = [
    haskellPackages.cabalInstall
  ];
})

Add any project dependencies to the buildDepends field. For this project, which uses Warp, add haskellPackages.warp:

buildDepends = [
  haskellPackages.warp
];

Launch a Nix shell, which will include cabal and ghc on the $PATH, as well as Warp and its dependencies:

$ nix-shell

From Nix shell, build the project with ghc:

[nix-shell]$ ghc Main.hs

The output includes an executable binary:

$ ./Main
$ curl http://localhost:3000/
<h1>Hello, world!</h1>

The compatible way

If the project sources are to be used by non-Nix users, it's more common to use Cabal.

To get Cabal on the $PATH, again fire up Nix shell. This time, instead of default.nix, package parameters are provided:

$ nix-shell -p haskellPackages.cabalInstall haskellPackages.ghc haskellPackages.warp

Depending on the configuration of the system, additional packages (e.g. zlib, pcre) may be necessary as well.

Create a new Cabal configuration file with cabal init:

$ cabal sandbox init
$ cabal init

Guessing dependencies...

Generating LICENSE...
Generating Setup.hs...
Generating hello-warp.cabal...

This creates a nice, coventional, Cabal configuration in hello-warp.cabal.

Grab any needed dependencies:

$ cabal install -j --only-dependencies

Build the project:

$ cabal build

Fire it up:

$ dist/build/hello-warp/hello-warp
$ curl http://localhost:3000/
<h1>Hello, world!</h1>