Setting up Haskell in VS Code with Stack and the IDE Engine

I love VS Code. I love how stripped down it is compared to “enterprise” IDE’s. I love how it runs on your favorite brand of OS, be that Windows, macOS, or Linux. But most of all, I love how easy it is to integrate the language of your choice with the editor.

Search for an extension, click install, and away we go. I’ve been using it for Javascript, Elm, Purescript, ReasonML, F#, and Python development, all without a hitch. The language extensions are universally first rate, with the Ionide plugin for F# development especially impressive.

And once you’ve become familiar using the editor with a language you already know, then it’s trivial to start exploring a language you’ve always wanted to learn. So let’s learn a new language!

All the code for this tutorial can be found here.

Hmm?!? Where to start?

The Haskell Tool Stack

Thankfully, there is a simple way to get started with Haskell, the Haskell Tool Stack, and we’ll set it up with homebrew.

Make sure you’re on the latest version of Xcode and type the following into the terminal.

brew install haskell-stack

Now starting a new project is a breeze.

stack new my-project
cd my-project
stack setup

The setup command actually downloads the compiler to an isolated location, so it won’t interfere with any other installations of Haskell on your system. And now we can startup VS Code.

code .

From Editor to IDE

Yuck! Let’s spruce this poor file up a bit.

The first extension to install is the syntax highlighter. Click install and reload and our sad looking file has gotten a little happier.

Linting Extension

After installing you’ll probably see an error like the following.

Unlike, the syntax highlighter we need to do a little bit of configuration grunt work to get the linter extension working.

stack install hlint..Copying from /Users/dogwith1eye/.stack/snapshots/x86_64-osx/lts-7.9/8.0.1/bin/hlint to /Users/dogwith1eye/.local/bin/hlint

Stack will copy the package into our ./local/bin folder, but the hlint path in our Preference file just points to hlint.

What we need to do is add ~/.local/bin to the path in our bash profile.

Open up the .bash_profile in textedit or the editor of your choice and add the following line.

export PATH=$PATH:~/.local/bin

Close down VS Code, crack it back open and Voila! An even happier file!

Language Server

But, before we can install the plugin, we need to install the haskell-ide-engine for the version of Haskell that Stack has set our project up with. First, let’s check what version of the compiler our project is using.

stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 8.6.4

Stack has configured version 8.6.4 of the compiler for me. So let’s change directories and download the haskell ide engine alongside our project.

cd ..
git clone https://github.com/haskell/haskell-ide-engine --recurse-submodules
cd haskell-ide-engine

Now we need to install the version of the haskell ide engine for compiler version 8.6.4. This seems to take a while, at least on my box, so grab some coffee before running the following.

stack ./install.hs hie-8.6.4
stack ./install.hs build-doc-8.6.4

And finally we can install the actual plugin.

Switching over to our code file we should see the following information about the IO monad when we hover over its definition. Super happy!

Debugging Extension

cd ../my-project
stack install phoityne-vscode

Testing out the Debugger

stack test...Test suite not yet implemented

By default our Spec.hs file simply prints to the console that we haven’t set anything up yet. Let’s fix that using the advice from this article. First we’ll alter our package.yaml and add a version of hspec to the dependencies section.

And let’s build our project with the new dependency.

stack build

Next, we’ll remove everything from our Spec.hs file and replace it with the following option to automatically discover and run all the spec files in our test suite.

{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

For some reason, I get an error about not being able to execute hspec-discover. I got around this by following the advice on this thread and installing hspec-discover to my global binaries.

stack install hspec-discover

And centralize all the dependencies in our test suite with the following SpecHelper.hs file.

Let’s create a function we want to test out.

And finally, we’ll write the actual Spec module to test out our function.

Our project tree should like the following. Remember, unlike a language like F#, in Haskell we have to create folders to correspond to our module declarations.

Running our test now results in the following.

And finally we get to test out actually debugging our spec file. Click on the debug tab of VS Code and choose haskell-debug-adapter, add a breakpoint to our MathSpec file. press F5 to start debugging, and we hit the breakpoint to start debugging our spec. Woot woot!

Remember, all the code for the project can be found here.

Now We’re Ready to Learn Haskell

And so why should we learn Haskell in particular?

Becasue Haskell makes us better programmers. Haskell forces us to solve problems in different ways and forces us to be up front about the side effects we rely upon. At first this may be frustrating, or intimidating, but over time you’ll start finding the ways we used to solve problems (mutations, hidden side effects, iteration) are frustrating and intimidating. Have fun!

A programmer looking for ways to see the forest instead of the trees.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store