Nix package manager

June 05, 2015

References

Haskell

To search packages in the haskellPackages namespace:

$ nix-env -f "<nixpkgs>" -qaP -A haskellPackages

To install packages, which live in the haskellPackages namespace, use -A:

$ nix-env -f "<nixpkgs>" -i -A haskellPackages.ghc

See User's Guide to the Haskell Infrastructure for more information.

To fix various libz.so problems, use nix-shell:

$ nix-shell -p zlib zlibStatic

To use the latest Agda, pull the latest nixpkgs and install directly:

$ nix-env -f /path/to/nixpkgs -i -A haskellPackages.Agda

To list all known Haskell compilers in Nix:

$ nix-instantiate --eval -E "with import <nixpkgs> {}; lib.attrNames haskell.compiler"

nix-repl can also be used to do this:

$ nix-env -i nix-repl
$ nix-repl
nix-repl> :l <nixpkgs>
nix-repl> haskell.compiler.ghc<Tab>

Nix shell

Use nix-shell to set up a temporary environment with dependencies that aren't needed in your daily environment.

$ git clone https://github.com/mszep/pandoc_resume
$ cd pandoc_resume
$ vim resume.md
$ make resume.pdf
make: command not found

Well, shoot. I don't have make installed. Even if I did, this project's Makefile requires both pandoc and context, and I don't have those installed either.

I don't really want to have to install make, pandoc, and context just to try this thing out. With Nix, I don't have to.

Let's try running make again, letting Nix handle the dependencies:

$ nix-shell -p gnumake pandoc texLiveFull --run 'make resume.pdf'

It worked! But now I have make, pandoc, and context installed, right? I didn't want that.

$ make
make: command not found

$ pandoc
pandoc: command not found

$ context
context: command not found

Nope! Immutable configuration is immutable.

Note: context might need mtxrun --generate run once before it's used.

Adding a new package to nixpkgs

See nixpkgs/15731.

Hoogle

$ nix-env -f "<nixpkgs>" -i -A haskellPackages.hoogle
installing ‘hoogle-4.2.43’

$ hoogle data -d ~/.hoogle
0 warnings, saved to .warnings
Data generation complete
$ hoogle '(>>=)' -d ~/.hoogle
Prelude (>>=) :: Monad m => m a -> (a -> m b) -> m b
Control.Monad (>>=) :: Monad m => m a -> (a -> m b) -> m b
Control.Monad.Instances (>>=) :: Monad m => m a -> (a -> m b) -> m b

Haskell development with Nix

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>

Simpler Haskell development with Nix

If you use Nix, here's a super simple way to do rapid development in Haskell. This approach simplifies those in Haskell development with Nix, which rely on tedious one-off Nix configuration files and Cabal.

Create a function nix-haskell in your shell configuration file:

~/.bashrc:

function nix-haskell() {
  nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [$@])"
}

This will start a nix-shell instance with GHC, and an environment configured with the list of packages that you supply as arguments:

$ nix-haskell random
[nix-shell]$

Now you can write library-dependent Haskell code without needing Cabal, Stack, etc.

Slug.hs:

{-# LANGUAGE OverloadedStrings #-}

import Control.Monad (replicateM)
import System.Random (randomRIO)

alphabet :: String
alphabet = ['a'..'z'] ++ ['0'..'9']

randomElem :: String -> IO Char
randomElem l = randomRIO (0, ((length l) - 1)) >>= \d -> return (l !! d)

main :: IO ()
main = do
  slug <- replicateM 12 (randomElem alphabet)
  putStrLn $ "Random slug: " ++ slug
[nix-shell]$ runhaskell Slug.hs
Random slug: 2tm997e9ko1p

This post is literate Haskell. Try running it with codedown:

$ nix-haskell random
$ curl -s https://earldouglas.com/posts/nix-haskell-2.md |
  codedown haskell |
  runhaskell
Random slug: m6n9t3xm9pvy

Developing Idris with Nix

Write an .idr file:

hello.idr:

main : IO ();
main = putStrLn "Hello, world!";

Start a shell with the Idris Haskell package and GMP:

$ nix-shell -p haskellPackages.idris gmp

Compile and run the program:

$ idris hello.idr -o hello
$ ./hello
Hello, world!

References

Nix recipes

This is an index of simple Nix expressions for handy reference.