New package management tool Stack

Recently FPComplete released a new package management tool called stack. This makes getting up and running with Haskell development a hell of a lot nicer than it was previously with cabal alone. Cabal is so hairy that there is a well know term "cabal hell" used to describe some of the common problems that it can cause.

Haskell is a pretty amazing language that has a lot of good ideas and I think it should be used a lot more in the industry. One of the things that has been holding it back from wider adoption has been the confusing and frustrating state of the main package management tool cabal. Stack is looking like a very nice solution to that problem and I hope a lot more people start experimenting with Haskell now.

How to get up and running as a newbie (on osx/linux)

Daniel Mlot recently wrote an article explaining a nice workflow with stack: casual hacking with stack. It can be a bit strange to get set up with Haskell at first so I thought I would put together a few simple steps for Haskell beginners.

Install stack

Follow the instructions for installing stack on your platform. This should be nice and easy for OSX/linux. (I haven't set up Haskell on windows yet so I'm not sure how well supported it is there.)

You should now have the stack binary on your $PATH somewhere (most likely in ~/bin/).

$ stack --version
Version 0.1.2.1, Git revision 09a9fa46fd1d8174ececf4a53774a05b36641457

Note: You may have a different version but that's ok.

Create a new project

Now you are ready to make a new haskell project!

$ mkdir hello-haskell
$ cd hello-haskell/
$ stack new

Writing: LICENSE
Writing: Setup.hs
Writing: app/Main.hs
Writing: hello-haskell.cabal
Writing: src/Lib.hs
Writing: test/Spec.hs
Writing default config file to: /Users/aaron/CodeBases/hello-haskell/stack.yaml
Basing on cabal files:
- /Users/aaron/CodeBases/hello-haskell/hello-haskell.cabal

Checking against build plan lts-2.17
Selected resolver: lts-2.17
Wrote project config to: /Users/aaron/CodeBases/hello-haskell/stack.yaml

We make a new directory hello-haskell and then run stack new within it. Stack creates a template project named after the directory.

$ ls -R
LICENSE             Setup.hs            app                 hello-haskell.cabal src                 stack.yaml          test

./app:
Main.hs

./src:
Lib.hs

./test:
Spec.hs

Let's build and run the new project:

$ stack build
hello-haskell-0.1.0.0: configure
Configuring hello-haskell-0.1.0.0...
hello-haskell-0.1.0.0: build
Building hello-haskell-0.1.0.0...
Preprocessing library hello-haskell-0.1.0.0...
[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-osx/Cabal-1.18.1.5/build/Lib.o )
In-place registering hello-haskell-0.1.0.0...
Preprocessing executable 'hello-haskell-exe' for hello-haskell-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-osx/Cabal-1.18.1.5/build/hello-haskell-exe/hello-haskell-exe-tmp/Main.o )
Linking .stack-work/dist/x86_64-osx/Cabal-1.18.1.5/build/hello-haskell-exe/hello-haskell-exe ...
hello-haskell-0.1.0.0: install
Installing library in
/Users/aaron/CodeBases/hello-haskell/.stack-work/install/x86_64-osx/lts-2.17/7.8.4/lib/x86_64-osx-ghc-7.8.4/hello-haskell-0.1.0.0
Installing executable(s) in
/Users/aaron/CodeBases/hello-haskell/.stack-work/install/x86_64-osx/lts-2.17/7.8.4/bin
Registering hello-haskell-0.1.0.0...

$ stack exec hello-haskell-exe
someFunc

So the template app is built and prints out "someFunc" when you run it. Let's change that. Open up app/Main.hs in your favourite editor (Vim and Emacs seem to be the most popular for Haskell development currently).

This is what it looks like currently:

module Main where

import Lib

main :: IO ()
main = someFunc

Change the main function to this:

main = do
  putStrLn "hello world!"

Now build and run it again:

$ stack build
$ stack exec hello-haskell-exe
hello world!

If you want to add a library from the list of stackage packages all you need to do is add it to the build-depends section of the haskell-hello.cabal file. The list of available packages is here: https://www.stackage.org/lts-2.19

...

executable hello-haskell-exe
  hs-source-dirs:      app
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , hello-haskell
  default-language:    Haskell2010

...

For example let's display some cpu information. Modify the build-depends section to look like this:

...
  build-depends:       base
                     , cpu
                     , hello-haskell
...

Save the file and run stack build again. Stack will download the package and install it ready to use. We can now use the cpu package in the Main.hs file. Alternatively we can also open up the ghci repl and import the cpu package.

$ stack ghci
Configuring GHCi with the following packages: hello-haskell
GHCi, version 7.8.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package cpu-0.1.2 ... linking ... done.
[1 of 1] Compiling Lib              ( /Users/aaron/CodeBases/hello-haskell/src/Lib.hs, interpreted )
Ok, modules loaded: Lib.
λ: import System.Arch
λ: getSystemArch
X86_64

The ghci repl can be quite handy for quick testing cycles while you're working on a project. Let's add a simple function to the Main module and reload the code into the ghci repl without having to restart ghci:

module Main where

import Lib
import System.Arch

main :: IO ()
main = do
  putStrLn "hello world!"

showSystemArch = "The cpu architecture is: " ++ (show getSystemArch)

Now back in ghci we can run :reload to recompile and then have access to our new function:

λ: :reload
Ok, modules loaded: Lib.
λ: :l Main
[1 of 2] Compiling Lib              ( /Users/aaron/CodeBases/hello-haskell/src/Lib.hs, interpreted )
[2 of 2] Compiling Main             ( /Users/aaron/CodeBases/hello-haskell/app/Main.hs, interpreted )
Ok, modules loaded: Lib, Main.
λ: showSystemArch
"The cpu architecture is: X86_64"

You now should have the basic tools set up to start hacking on Haskell projects easily. There's a lot of great free resources for learning Haskell, some good ones are:

Once you have the basics down Ollie Charles' blog has a great exploration of some of the more popular Haskell libraries currently in use: