Building Haskell Projects

For this class, we recommend you use the new Stack Haskell build system. You will see many references to Cabal and cabal-install on the Internet for Haskell projects. This document tries to quickly explain the situation.

Our motivation for recommending Stack is that we believe it is easier for beginners to work with, particularly as it manages the version of GHC used so that you aren't reliant on your OS package manager.

We will be using GHC 7.10 throughout this course.

Stack

Stack is a build system for Haskell that aims to give you extremely reproducible builds. To do this, it manages (and freezes) all your dependencies and the version of GHC being used for your project.

Stack is backed by the Stackage package system. Stackage uses the concept of 'snapshots', where all packages part of the same snapshot are meant to be compatible with each other. When installing a new package, you don't choose which version to install, instead when starting a project using Stack, you choose which Stackage snapshot to use. After that, all package versions are fixed, determined upstream by Stackage's snapshot mechanism.

Stack vs Cabal

Cabal is the package description format for Haskell. It describes what a package is and how packages interact with the language. It also provides common infrastructure for building and distributing packages.

Traditionally, Haskell programmers used a tool called cabal-install that knows how to build a Cabal package. cabal-install also interacts with a package hosting website, Hackage, for retrieving dependencies during the build process.

Each time a client of cabal-install configured a package to prepare it for building or installation, cabal-install would perform dependency resolution, resolving which version of packages A, B and C to use, such that all packages chosen are compatible with each other and all dependencies are satisfied. This works, but led to a problem known as 'cabal-hell' (similar to DLL-hell on Windows), where cabal-install would fail to find a way to solve the dependency problem. This was particularly bad due to the use a single global package installation location, meaning all projects had to have compatible versions of packages. cabal-install later adopted a 'sandbox' strategy where a project could install dependencies local to the project, which helps greatly.

However, cabal-install doesn't do a great job of giving developers reproducible builds. It may resolve package A to version 1.0 on one developers machine, and resolve package A to version 1.1 on a different developers machine if run at different times. It also doesn't manage GHC itself, considering that out of scope.

Stack and it's backing website, Stackage, instead solve this problem globally and once for everyone. They create a set of packages called a 'snapshot' where they try to guarantee that all packages part of a snapshot are compatible with each other and have all their dependencies contained in the snapshot. A project using Stack simply declares the snapshot they are using, and no dependency resolution needs to be performed. Stack also manages the version of GHC used as part of a snapshot.

Stack in Relation to Cabal

Stack doesn't replace Cabal, but does replace cabal-install. It also doesn't replace Hackage, but provides 'snapshots' of it through Stackage.

Installing

See stack documentation, but we present the cliffs notes below.

Apple OS X

Probably the easiest way to install is using homebrew:

brew install haskell-stack

Arch Linux

Stack is only available in AUR at this moment. You'll likely need the following two packages:

Ubuntu

Full documentation

For Ubuntu 15.10:

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 575159689BEFB442
echo 'deb http://download.fpcomplete.com/ubuntu wily main' |sudo tee /etc/apt/sources.list.d/fpco.list
sudo apt-get update && sudo apt-get install stack -y

Configure Stack

First, configure some defaults:

$ vim ~/.stack/config.yaml

This file should look something like:

templates:
  params:
    author-email: rlloyd@richardlloyd.com
    author-name: Richard Lloyd
    copyright: Richard Lloyd
    github-username: rlloyd
    category: web

You can override these defaults on the command line:

stack new proj -p "category: testing"

Using Stack

stack new my-project
cd my-project
stack setup
stack build
stack exec my-project-exe

You can also load your project in GHCi (A Haskell REPL):

stack ghci

Or run your test suite:

stack test