Nix - Trying out Haskell with less hassle

Posted on June 9, 2020

I heard you want to try out haskell but like me you hesitate because you don’t know how to setup your enviroment for Haskell. Okay, hear me out. Nix can be the solution, I know you have to learn more. However, it’s not that much. At least that’s what I see. Just learn a little bit of nix now and learn as you go!

So if I convinced you to learn a little bit of nix. Go ahead and download it from their website.

Now, instead of worrying what system configuration you have to do, you just do this

mkdir my-project
nix-shell --pure -p ghc cabal-install --run "cabal init"

What’s happening here is you’re telling nix to go get ghc(compiler) and cabal-install(build tool), and run the command cabal init. This will generate a very small scaffold for a haskell project. Since we used the flag --pure it won’t install anything global in your system.

Your my-project directory should look like this

my-project
|-- CHANGELOG.md
|-- Main.hs
|-- my-project.cabal
|-- Setup.hs

Main.hs should contain the Hello World program. This is also where you want to write your experiment haskell code.

Since you used ghc and cabal in a pure environment you won’t find them when you try to execute cabal in the console. So you won’t be able to run this project as is. What you can do is play with your haskell project in a nix-shell. You can do this by first generating a default.nix file. This can be done by doing this command in your project directory

nix-shell --pure -p cabal2nix --run "cabal2nix ." > default.nix

This will generate the default.nix file and will contain

{ mkDerivation, base, stdenv }:
mkDerivation {
  pname = "my-project";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base ];
  license = "unknown";
  hydraPlatforms = stdenv.lib.platforms.none;
}

This file describes your project. It’s like a function that takes in nix stuff.

For the last part, write the shell.nix file.

{ nixpkgs ? import <nixpkgs> {} }:

let
  inherit (nixpkgs) pkgs;
  inherit (pkgs) haskellPackages;

  project = haskellPackages.callPackage ./default.nix {};

in
pkgs.stdenv.mkDerivation {
  name = "my-project";
  buildInputs = project.env.nativeBuildInputs ++ [
    haskellPackages.cabal-install
  ];
}

When you perform nix-shell --pure in your project directory. It will go into a nix environment and you’ll see your command prompt turn like this

[nix-shell:~/my-project]$

In this environment you’ll have access to cabal. So you can build and run your project with cabal new-build and cabal new-run.

If you want to expirement with a haskell package from hackage like the text package, you can add it to your my-project.cabal file, in the build-depends section.

cabal-version:       >=1.10
-- Initial package description 'my-project.cabal' generated by 'cabal
-- init'.  For further documentation, see
-- http://haskell.org/cabal/users-guide/

name:                my-project
version:             0.1.0.0
-- synopsis:
-- description:
-- bug-reports:
-- license:
license-file:        LICENSE
-- author:
-- maintainer:
-- copyright:
-- category:
build-type:          Simple
extra-source-files:  CHANGELOG.md

executable my-project
  main-is:             Main.hs
  -- other-modules:
  -- other-extensions:
  build-depends:       base >=4.13 && <4.14
                     , text
  -- hs-source-dirs:
  default-language:    Haskell2010

You should also add this to your default.nix file, so later on when you do decide to build your project with nix-build you don’t have to chase around packages. I’ll probably cover nix-build in another post.

{ mkDerivation, base, stdenv, text }:
mkDerivation {
  pname = "my-project";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base text ];
  license = "unknown";
  hydraPlatforms = stdenv.lib.platforms.none;
}

Acknowledgements

Getting Started Haskell Project with Nix - Soares Chen

Nix Shorts - Justin Woo