Getting Started with Haskell
I’ve been playing around with Haskell recently as a way of clearing my head from the day job doing Python. It turns out getting a working setup is surprisingly difficult, so I’ve written this guide to help those attempting to learn Haskell get started. It explains:
- How to install the Haskell compiler and development tools. The tools include the
cabal
build & dependency-management app; theghc-mod
IDE support tool; thestylish-haskell
code-formatter; and thehi
(“Haskell init”) project-scaffolding tool - How to install and configure an IDE and REPL
- How to use the
hi
(Haskell Init) project-scaffolding tool to initialise a new project. - What are the best Haskell learning-resources
There are some tips for Mac users in particular.
One of the problems with Haskell is determining how install the particular versions of each of these tools that work well together, as they can often conflict. In recent times, the Stackage project has been launched by the people at FP Complete to address this. Similar to a Linux distribution, Stackage maintains a collection of particular Haskell libraries (“packages”) and applications, at specific versions, which are all tested to not only be stable themselves, but stable with respect to each other. However as there is no IDE support for Stack at the moment, I won’t discuss it here.
Setting Up Haskell
The minimum version to target for GHC is 7.10, and for Cabal, it’s 1.22.
Users of Mac OS X will first need to ensure they have the command-line development-tools installed. To do this install XCode from the app-store, then on the command-line run the following (note the dashes).
sudo xcode-select --install
sudo xcodebuild -license
Next, Mac users, and also Windows users, should install the Haskell Platform.
For Linux users, of course, the first option is their native package manager; however if that doesn’t have GHC 7.10, then they too should use the Haskell platform.
Once done, you should have ghc
, ghci
, runghc
, and cabal
all on your path. GHC is the compiler obviously, ghci
is a simple REPL, and runghc
compiles and runs the given script.
Cabal is a build & dependency-management tool similar to Maven for Java, but it can also install standalone executables. As a first step, you should ensure you have the latest version of Cabal itself installed. Type:
cabal update
cabal install cabal cabal-install
For those who are confused, cabal is the library and cabal-install is the application called – somewhat confusingly – cabal
.
When you execute the commands above it will tell you where all applications installed by typing cabal install appname
will be placed on your filesystem. On Macs using the Haskell platform, it’s $HOME/Library/Haskell/bin
. Make sure to update your PATH environment variable accordingly.
A Mac(Ports) Conundrum
Haskell and MacPorts don’t always play well together. Some third-party Haskell libraries (or “packages”) when being built will opportunistically link to libraries in the MacPorts installation directory, /opt/local
. This directory includes libraries duplicating those on the system, notably libiconv
. This can then lead to linker errors when the wrong iconv library is picked up by the linker. You can read an in-depth description of the MacPorts library problem here, but the short answer is that if you have linker trouble when building an application, particularly if it involves iconv and HSBase, you may want to try amending the project configuration and rebuilding by typing
cabal configure --extra-lib-dir=/usr/lib
cabal build
This will force a search of /usr/lib
before the MacPorts’ directory. For whatever reason, the relocatable GHC package is less affected by this but that does not currently (February 2016) work on Mac OS X “El Capitan”.
Installing an IDE
As of February 2016, I have found no process which is guaranteed to always provide a new user with an IDE that works reliably, at least not on a Mac.
The IDE Haskell plugin which works with the Atom editor is the most promising at the moment, however while I’ve got it to work with GHC 7.10, it was after several false starts. Ghc-mod, on which it relies, will often crash out silently due to malformed Haskell or Cabal files, in which case you need to relaunch the editor. At other times, ghc-mod will launch some expensive, long-running process that confuses Atom.
The IntelliJ IDEA plugins, both IntelliJ’s own and HaskForce similarly struggle with GHC 7.10 and ghc-mod.
The EclipseFP plugin used to work very well indeed, but it relies on a tool called buildwrapper
which ironically will not build with GHC 7.10 & Cabal 1.22
The Leksah application is a Haskell IDE written in Haskell which will definitely work. Visually it looks very poor on both Mac OS X and Windows, and it has an unorthodox and noisy layout that takes time to get used to.
Therefore the next best approach after Atom/IDE-Haskell, is to use the web-based IDE provided by FP Complete. While guaranteed to work, this obviously this requires a constant internet connection, and a github hosted project.
Since Atom, when it works, works very well indeed, it’s worthwhile trying to install and configure it however, which is what we describe next.
Atom IDE-Haskell Installation
Install Atom from its website and then use the command-line and cabal to install the Haskell IDE support tools:
cabal install happy
cabal install ghc-mod hlint hoogle stylish-haskell
Happy needs to be installed first and separately as it is an undeclared dependency of haskell-src-exts
, which is in turn required by ghc-mod
.
Then launch Atom and install the following packages:
- haskell-ghc-mod
- autocomplete-haskell
- language-haskell
- ide-haskell
You will likely need to configure each of these individually to enter the full paths to cabal, ghc, ghc-mod etc. When editing the settings for haskell-ghc-mod you enter both the path to the cabal installation directory (e.g. /Users/myusername/Library/Haskell/bin
) and the path to ghc (e.g. /usr/local/bin
) to the “Additional Path Directories” field, the pair separated by a comma.
Then quit Atom, find a Haskell project (or create one as shown below) and restart Atom.
Add the project directory using the “Add Project Folder” item of the “File” menu, then open its Cabal file to trigger the launch of the Haskell IDE support, complete with its eponymous “Haskell IDE” menu. If you’re lucky, autocompletion, error-detection, linting and building tools will all become available.
Before opening a project with Atom, you may want to consider “test-driving” ghc-mod by launching it from the command-line with a sample file to check, using
ghc-mod check /path/to/file.hs
. GHC-Mod does occasionally do some very time-consuming work such as building its own cabal, and this tends to confuse IDEs mightily. Moreover, before you launch either Atom orghc-mod
for the first time on a new project, you should ensure that runningcabal build
works first.
The IHaskell REPL
A good REPL is invaluable when learning a new language, a new library, or just playing around with ideas. IHaskell is the best Haskel REPL I’ve come across.
It’s based on IPython Notebook, a web-frontend that lets you interleave markdown and live code in a virtual notebook. In 2015 this was split into two projects, a “Jupyter” core and a Python plugin. This was to explicitly accommodate other languages, such as Haskell, using the IHaskell plugin.
Linux users can install Jupyter using their package manager, though depending on their distribution it may still be called ipython, and then install ihaskell using
cabal install ihaskell
ihaskell install
Once installed, launch the notebook server by typing ipython notebook
. Despite the name, you will see you will have the option of creating either Python or Haskell notebooks.
For OS X users you can use Homebrew to install Python, then Pip to install ipython, and finally cabal to install IHaskell as shown above. Should you try to install Python and IPython using MacPorts, you immediately encounter the usual MacPorts / system library linking issues. The easiest, though spectacularly wasteful, solution to this is to install Kronos Haskell which is a 2GB app bundle with its own copies of Python, Jupyter, GHC, Cabal and the usual Haskell libraries.
For windows users, the Kronos option is by far and away the simplest approach.
Creating your first project
We’ll use the Haskell Init tool. If you haven’t already installed it, do so by opening a console and typing
cabal install hi
To create a project called my-project-name
in a directory called my-project-dir
type
hi --repository git://github.com/tfausak/haskeleton.git \
--directory-name my-project-dir \
--package-name my-project-name \
--module-name MyProjectName \
--author "Bryan Feeney" \
--email bryan@amixtureofmusings.com
The repository flag is not the new project’s repository; rather it gives a path to a template project, in this case the Haskeleton template. This features unit-tests, documentation tests and benchmarks, with all of these explained in the Haskeleton guide. Other project templates, such as web-apps, can be found on the HI templates page)
Module names, which are camel-cased, are used in Haskell code while package names, which are dashed, are used on the Hackage package repository.
Before you start coding, you’ll want to download the skeleton project’s dependencies. Rather than mix these dependent packages in with your global package repository, create a local package sandbox for your project:
cd my-project-dir
cabal sandbox init
cabal update
cabal install --only-dependencies
cabal install --enable-test --only-dependencies
cabal install --enable-bench --only-dependencies
Cabal can automatically detect a sandbox, so once it’s created you can just use the usual commands. Typing cabal install --only-dependencies
installs the project’s dependencies as given in the Cabal file. By default this is for the library and/or executable only. You need additional calls to download and install any dependencies required for the unit-tests and benchmarks.
As a quick check, make sure everything builds:
cabal build
And then you’re safe to open the project in Atom. Obviously you can also run tests using cabal test
, and execute the benchmarks using cabal bench
, though if you want benchmarks presented as graphs rather than ASCII text, type:
mkdir -p dist/bench
cabal bench --benchmark-options="--output dist/bench/index.html"
Note benchmarks are only available with the Haskeleton project template.
Actually Learning Haskell
There are two free online resources that are popular:
- Learn You a Haskell (LYAH) is very slightly out of date[1], is extremely readable, but ends without ever demonstrating how to code, let alone design, a full application
- Real World Haskell tends to work through doing things the hard way before showing how they can be done simply - an approach which makes learning Haskell unnecessarily tedious. At one point it was very useful, as it tackled typical programming problems. Unfortunately it is now horribly out of date, and while commenters have provided corrections, there’s not much they can do when the book uses entirely the wrong (by contemporary standards) libraries for things such as regular expressions.
This is a case where the best approach is to actually buy a book, in this case Beginning Haskell: A Project-Based Approach. While obviously more expensive than free, it pays its own way in terms of time saved.
Once you’ve learnt the core language, you will likely find What I wish I knew when learning Haskell to be a useful read. It is a sort of Haskell-by-example, describing all the practical aspects of application development you need to be aware of. Particularly if you’ve learnt Haskell from Learn You a Haskell (LYAH), this is the recommended next step.
Similarly the 24 Days of … guides by Oliver Charles offer a nice introduction to the various Haskell packages and extensions that are commonly used.
1. Specifically the eponymous constructors for the State
, Writer
and Reader
monads have all been hidden, and instead replaced with lower-case functions state
, writer
and reader
, affecting the code examples in chapter 13.