My Haskell VS Code Setup in 2021
Power up your IDE with debugging, autocompletion and other Haskell features
Recently, I started learning Haskell. The first thing you have to do when dabbling in a new language is the development environment configuration. I like VS Code and work primarily in it. Therefore, I had no doubt which editor I’ll use during my learning.
The first thing I did was a quick search for the articles on Medium that would help me to configure the editor. Setting up Haskell in VS Code with Stack and the IDE Engine by Matthew Doig is a good place to start yet it’s a bit outdated. Therefore, I decided to write something similar but with more up-to-date information.
Another point I wanna outline beforehand, I’m using macOS, so keyboard shortcuts and other stuff were tested on the said OS. It may work differently on your laptop or PC.
So, the main problem is that by default VS Code shows no sign of supporting Haskell. Yet the problem could be easily eliminated by following a few simple steps.
Okay, let’s start from here then.
Step 0. Get Yourself VS Code
Go to VS Code main page and download the installer for your OS of choice.
From now on, I’ll presume you have VS Code installed, so let’s move on to actually configuring it :)
Step 1. GHCUp It
GHCup is an installer for the general purpose language Haskell.
GHCup is the easiest way to install everything you need to bootstrap your Haskell journey: compiler, packaging and distribution systems, and so on. Sounds great, should we try it out? For sure.
Open the terminal, either inside of the VS Code, or as a stand-alone program, and run the following command inside of it:
$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
The program will ask you whether you want to add all the required stuff to your .zshrc
or other shell config files. I prefer the appending option, though you’re free to choose for yourself:
After that, GHCup will propose to install Haskell Language Server and stack. These two will definitely come in handy later on, so “Yes” is the answer:
As soon as we’ve chosen all the options we need the installation process should start:
Press Enter to proceed and wait for the whole process to complete. Just a suggestion: grab yourself a cup of tea as this may take a while.
Great, we’re all set. Let’s configure our VS Code now. We need to actually generate a new project for this. I prefer stack for this goal. Therefore, open a terminal window and type the following commands:
$ stack new vscode-haskell-config
$ cd vscode-haskell-config
$ stack setup
Step 2. Syntax Highlighting
The first thing we want to get from a text editor or an IDE is colorized code. It’s easy to achieve this by installing a dedicated extension:
Additionally, it may be needed to reload the editor, so be attentive. After the installation, the app/Main.hs
you saw at the beginning should look something like this, depending on your color scheme:
That’s definitely an improvement but it’s still quite far from the IDE functionality. In the previous section, we’ve added Haskell Language Server (HLS), and it’d be nice to enable its functionality in VS Code.
Step 3. Pump VS Code Up
The process of configuring the HLS is really complicated except it’s not. There are two simple steps you need to follow to make it work:
̶̶̶1̶̶̶.̶̶̶ ̶̶̶I̶̶̶n̶̶̶s̶̶̶t̶̶̶a̶̶̶l̶̶̶l̶̶̶ ̶̶̶H̶̶̶a̶̶̶s̶̶̶k̶̶̶e̶̶̶l̶̶̶l̶̶̶ ̶̶̶S̶̶̶y̶̶̶n̶̶̶t̶̶̶a̶̶̶x̶̶̶ ̶̶̶H̶̶̶i̶̶̶g̶̶̶h̶̶̶l̶̶̶i̶̶̶g̶̶̶h̶̶̶t̶̶̶i̶̶̶n̶̶̶g̶̶̶ ̶̶̶e̶̶̶x̶̶̶t̶̶̶e̶̶̶n̶̶̶s̶̶̶i̶̶̶o̶̶̶n̶̶̶.̶̶̶ ̶̶̶W̶̶̶a̶̶̶i̶̶̶t̶̶̶ ̶̶̶a̶̶̶ ̶̶̶s̶̶̶e̶̶̶c̶̶̶…̶̶̶ ̶̶̶W̶̶̶e̶̶̶ ̶̶̶f̶̶̶i̶̶̶n̶̶̶i̶̶̶s̶̶̶h̶̶̶e̶̶̶d̶̶̶ ̶̶̶i̶̶̶t̶̶̶ ̶̶̶j̶̶̶u̶̶̶s̶̶̶t̶̶̶ ̶̶̶a̶̶̶ ̶̶̶f̶̶̶e̶̶̶w̶̶̶ ̶̶̶m̶̶̶i̶̶̶n̶̶̶u̶̶̶t̶̶̶e̶̶̶s̶̶̶ ̶̶̶a̶̶̶g̶̶̶o̶̶̶…̶̶̶ ̶̶̶C̶̶̶o̶̶̶o̶̶̶l̶̶̶,̶̶̶ ̶̶̶h̶̶̶u̶̶̶h̶̶̶?̶̶̶ ̶̶̶T̶̶̶h̶̶̶u̶̶̶s̶̶̶,̶̶̶ ̶̶̶t̶̶̶h̶̶̶e̶̶̶ ̶̶̶s̶̶̶i̶̶̶n̶̶̶g̶̶̶l̶̶̶e̶̶̶ ̶̶̶s̶̶̶t̶̶̶e̶̶̶p̶̶̶ ̶̶̶l̶̶̶e̶̶̶f̶̶̶t̶̶̶.̶̶̶
1. Install HLS support extension:
Click the “Install” button and wait for the editor to do the remaining magic. Here you go. After installation, our turn-to-be IDE shows a red squiggle in our app/Main.hs
:
To resolve the issue we need to be inside the project’s directory in our terminal, and type these commands:
$ stack clean --full
$ stack build
Everything should be in color now:
HLS is an extremely useful tool. It provides our VS Code (and us, ofc) with:
- type information and documentation on hover
- autocompletion
- refactoring and code style suggestions from
hlint
- other handy features that are expected to get from an IDE
Any Code Formatting?
That’s a nice question. Actually, HLS provides you with those capabilities though I haven’t told you that on purpose. There are several formatting providers with a default called Ormolu. I strongly recommend you try them all and choose the one that will satisfy your needs and taste.
Nevertheless, my personal preference is Brittany. This is my article, therefore, you’re out of luck if expected to see something different here :)
Thus, I’ll show how you can easily change the formatting provider to Brittany.
In order to do so, press this combination on your keyboard Cmd + ,
or click Code -> Preferences -> Settings:
Ready? Great, moving further. Now type in “Haskell” in the settings’ search bar, and find the “Formatting Provider” section where you should see Ormolu selected:
Now, let’s actually select a different one, which is Brittany:
Okay, what if we want to ensure it actually works, because we don’t trust those fancy editors? First thing first, we need to add some code to see the formatting in action.
Let’s open the ./src/Lib.hs
file as we’ll be placing our brand new function there. You may erase the whole content of the file, no worries.
Please, retype the example with these inconsistencies as we’ll format it automatically.
Wait a sec… How do we use the formatter anyway? Press Opt + Shift + F
, and Brittany will do the heavy lifting.
Please, don’t worry if you don’t understand what’s going on, the point was to test the automatic formatting. It seems to work just fine :)
Haskell Code Debugging
Despite the notion that if Haskell code compiles it works as intended, the debugging capabilities may be useful. Unfortunately, HLS does not seem to bring a debugger (at least as of November 2021.)
Fortunately, this “weakness” is easily resolved by the installation of another cool extension.
Did you just install it? That awesome! We’re almost set to start debugging. Before the actual start, we have to a) add tests and b) configure the debugger.
a) Adding Tests
If we try to run the debugger without any tests, it’ll exit saying “Test suite not yet implemented”.
That’s exactly the thing we’re getting from running
$ stack test
We can observe this string in test/Spec.hs
:
Okay, fine. It seems we just need to implement some tests. Sounds reasonable.
We’ll be using QuckCheck for that. It’s an awesome library allowing us to do some property-based testing. We’ll write only one test for the pal
function as we need to test the debugger, and not write a proper test suite.
First of all, let’s add QuickCheck
to our project. Go to package.yaml
, and in the tests
section find the dependencies
subsection. Feel free to add the library as a dependency:
The dull part is almost over, we’re about to dive into the awesome world of property-based testing. Please, open the ./test/Spec.hs
file again. The important thing to decide in the beginning: what would be tested? Since we don’t have tons of options, just import the pal
:)
import Lib (pal)
The next step is adding another import, this time QuickCheck. After this, your Spec.hs
has the following contents:
import Test.QuickCheck
import Lib (pal)
Let’s write our first property test. We’re gonna name it prop_reverseInvariant
which checks that the pal
function applied to the reversed palindrome should also return True
.
import Test.QuickCheck
import Lib (pal)prop_reverseInvariant :: String -> Bool
prop_reverseInvariant text = pal text == pal (reverse text)
After some formatting with Brittany, the content of the file would be as follows:
Note. You may have encountered the following issue:
Warning: Installation path /Users/<username>/.local/bin not found on the PATH environment variable.
All you need to do in order to fix the issue is to add this to your .zshrc
or other shell configuration file:
export PATH=$PATH:~/.local/bin
b) Configuring the Debugger
Choose “Run and Debug” sidebar button in VS Code:
What’s next? We need to create a launch.json
file first, in order to configure all the stuff related to “how should the IDE run our debugger?” Do this by clicking “create a launch.json` file. Select haskell-debug-adapter
in the dropdown:
Congrats, the .vscode
directory with respective configuration was created in the root of the project. But… We’re interested in actually running the debugger and not doing all that boring stuff. Please, be patient :)
Add a few lines to the test/Spec.hs
file:
main :: IO ()
main = do
quickCheck prop_reverseInvariant
Insert a breakpoint on line 9, and run the debugger with the haskell(stack)
option. Make sure it actually stops the execution, ’cause that’s the point :)
Have a Nice Haskell Journey with Configured IDE
That’s mostly it when we’re talking about setting the VS Code for Haskell. Now you have all the syntax highlighting and IDE functionality, as well as instruments to debug our code.
There might be other things useful in development such as ghcid. Though it has no connection to VS Code, thus, feel free to explore those tools by yourself :)
What are you waiting for? Enjoy learning Haskell and have fun! :)
UPD. I received some feedback on LinkedIn and Reddit, which I consider rather useful but don’t wanna take credits for.
You may find some interesting comments on r/haskell
thread. Check it out.
Another point I wanted to add was outlined by Ramón Soto Mathiesen (many thanks for that) on LinkedIn, regarding -with-rtsopts=-N -qg
GHC flag. This paste may make it clearer why you may need to add that.