path: root/tech/debstablehaskell.mdwn
diff options
Diffstat (limited to 'tech/debstablehaskell.mdwn')
1 files changed, 235 insertions, 0 deletions
diff --git a/tech/debstablehaskell.mdwn b/tech/debstablehaskell.mdwn
new file mode 100644
index 0000000..da3d96d
--- /dev/null
+++ b/tech/debstablehaskell.mdwn
@@ -0,0 +1,235 @@
+As of early 2015.
+I'm now [doing
+(under Debian) because some packages I want don't build with Debian
+Wheezy's versions of happy, alex and GHC.
+I'm trying to learn the Haskell programming language, and I'm tripping
+over the `cabal-install` package management system sufficiently often
+that it's putting me off putting time into learning the language. Here
+are my requirements for a development environment I'm willing to learn
+1. don't leave Debian Wheezy 32-bit;[^1]
+2. minimise how often I have to delete all of `~/.cabal` and `~/.ghc`;
+3. when using cabal sandboxes, again, minimise the number of core
+ libraries that need to get rebuilt in every sandbox;
+4. be simple enough to integrate cleanly with the existing ways I
+ manage my OS installation and the contents of my home directory;
+5. be simple enough that I can understand everything as a Haskell
+ beginner and can get things working (again) quickly and get back to
+ trying to write Haskell.
+In this document I will describe the combination of home directory and
+system-wide installations that fit these requirements, and the workflow
+for sorting out packages so that I can get on with trying to make my
+programs do input and output, and other fun Haskell beginner stuff.
+Alternative approaches
+The following two approaches don't satisfy the requirements given above.
+### Do everything manually
+This involves having nothing installed system-wide, including the
+Haskell Platform. Install GHC and Cabal in `~/local/src` and then
+install things into their own sandboxes and add the `.cabal-sandbox/bin`
+directories to your `$PATH`. [Someone on reddit
+a balance between installing stuff into `.cabal/bin` and having
+sandboxes in which related packages are built and then symlinking those
+directories. But this requires lots and lots of rebuilding over and over
+and lots of manual `$PATH` additions. System-wide Debian packages
+mitigate this.
+[This]( might facilitate
+such an approach.
+Fails (2), (3) and (4).
+### Use a clever automatic sandboxing solution
+[Halcyon]( and the [Nix package
+(which doesn't require the full NixOS) are the projects I've come across
+that try to do this. They aim to avoid even more rebuilding than my
+approach avoids. The Halcyon author [doesn't want to support 32-bit
+Debian](, and I don't want to
+be a Nix early adoptor at the same time as trying to learn how to get my
+programs to take input and produce output.
+Fails (1) and (5).
+Drawbacks of my approach
+We're living very far away from the edge: we're using GHC 7.4 and a
+version of the Haskell Platform from 2012. [Someone on reddit
+the view that since Haskell moves so fast, you'll end up rebuilding
+everything all the time anyway so you can use your favourite packages
+from Hackage. The only thing we're not getting from the Debian apt
+repositories that we might is `haskell-mode` and `ghc-mod` for Emacs,
+since we can have newer versions of those without repeated building.
+We're doing a lot of rebuilding of libraries, and we're only avoiding
+rebuilding those that come with Debian, which will become less and less
+useful as time goes by and Hackage packages depend on newer versions.
+This is okay because I'm a Haskell beginner, and I'm not a professional
+software engineer, so even if I stick with learning Haskell it's going
+to take me years before I'm writing anything that needs fancy
+contemporary libraries. And maybe by then the `cabal-install` ecosystem
+will have improved. I basically need Hackage only for building fancy
+things like [Propellor]( and
+[Structured Haskell
+Mode]( so it's okay
+to sandbox those things and do a load of builds.
+System setup
+Debian packages and dotfiles
+Get all our basic libraries installed system-wide:
+``` {.nil}
+# apt-get install ghc ghc-prof haskell-platform
+or if you're using [Propellor](
+``` {.haskell}
+workstationAptPackages :: Property NoInfo
+workstationAptPackages = combineProperties "workstation apt packages"
+ [ Apt.installed ["ghc", "ghc-prof", "haskell-platform"]
+ , Apt.removed ["haskell-mode", "ghc-mod"]
+ ]
+Put cabal configuration file in place:
+The most important thing here is `require-sandbox: True`. We're not
+putting **anything** in `~/.cabal/bin`. So we need to include all
+`.cabal-sandbox/bin` directories in our `$PATH`. I build stuff that is
+to be built on every machine in `~/local/src`. So for each binary we
+have a sandbox in a directory under `~/local/src`, e.g.
+`~/local/src/propellor`. This code will prepend those directories to
+`$PATH`. It comes from [my
+which is supposed to be a POSIX-compatible script to set up environment
+variables that I can source in `.zshrc`, `.bashrc`, scripts run from
+cron, my GNOME and XFCE startup scripts and wherever.
+``` {.bash}
+for bindir in $(find ~/local/src -path "*/.cabal-sandbox/bin"); do
+ PATH="$bindir:$PATH"
+export PATH
+Upgrading `cabal-install`
+Before doing anything else, we upgrade `cabal-install`. The version of
+cabal-install in Wheezy is so old that it doesn't know about sandboxes,
+and we don't want to pollute `~/.cabal/bin`. So we cheat and get it from
+``` {.nil}
+# apt-get install -t testing cabal-install
+Be sure to have [set up apt
+pinning]( so that this
+doesn't pull anything else in from Jessie!
+Upgrading `cabal-install` again
+Since we want the smartest dependency resolution we can get, we now
+upgrade cabal to the very latest and greatest.
+``` {.nil}
+$ cabal update
+$ cd ~/local/src
+$ cabal get cabal-install
+$ cd cabal-install-*
+$ cabal sandbox init
+$ cabal install
+Restart the shell (`hash cabal` isn't enough because we only just
+created the sandbox) and type `cabal --version` to check that the second
+decimal is higher than 20. Use `which cabal` to check that it's the one
+from `~/local/src`.
+Usage for Haskell projects
+Installing other people's programs
+Maybe you want the `ghc-mod` or `structured-haskell-mode` executables
+from hackage. Follow the procedure just used for upgrading
+`cabal-install` for the second time.
+Getting libraries for your project
+This section is a WIP. But some tips:
+- Basic workflow is `cabal init; cabal sandbox init; cabal build`.
+- Use `cabal repl` to launch ghci.
+- When you need a library, first try to find a debian package (the
+ name will begin with `[lib]ghc-`).
+- If you can't find it, you can use `cabal install blah` to install
+ into the sandbox for testing before adding to the .cabal file as
+ a dependency. Try to install all required packages in one go on one
+ `cabal install blah1 blah2` command as this gives cabal the best
+ chance of getting the dependencies right.
+- Don't be afraid to clear out the sandbox: `rm -rf
+ .cabal-sandbox-config .cabal-sandbox; cabal sandbox init`.
+- Try -v3 to enhance cabal's dependency resolution some more.
+Sources & further reading
+- Useful reddit threads
+ - [How to avoid Cabal
+ Hell](
+ - [Best practices for avoiding Cabal
+ Hell](
+- On configuring Emacs
+ - [Using Emacs for Haskell
+ development](
+ -- tools [I
+ use](
+ - [Modern Emacs
+ Haskell-Mode](
+ -- more experimental tools if you're willing to break out of
+ Wheezy etc.
+ - [and the reddit
+ thread](
+- More advanced stuff
+ - [Comprehensive Haskell
+ Sandboxes](
+- Background reading
+ - [How we might abolish Cabal Hell, part
+ 1](
+ - [The Cabal of
+ Cabal]( (I
+ think this is out-of-date)
+ - [Storage and Identification of Cabalized
+ Packages](
+[^1]: Debian Jessie will be out soon, but its versions of GHC and the
+ Haskell platform are still very old so upgrading early is not a way
+ out.