Debunking Haskell Myth: “Tooling Issue”

Zelenya - Feb 28 '23 - - Dev Community

📹 Hate reading articles? Check out the complementary video, which covers the same content: https://youtu.be/c7FncTzvpUQ


Haskell is covered with stereotypes and myths. And one of them is the idea that there exists a “Tooling issue” (with a capital T).

Maybe it was true back in the day. But anyways, I want to cover the current state of things and show some tooling that other language ecosystems can only dream about.

And, of course, there are some issues here and there; we’re all software engineers, and we know how it is.


We’re going to cover the following:

  • Installation tools
  • Build tools
  • IDE / Language server
  • Cherry on the top

🌚 Note that we’re not going to talk about Nix.


Speed-run

Today’s standard is to install GHCup, then use it to install the compiler (GHC), the build tools (Cabal, Stack, or both), and the language server (HLS). Afterward, you install VSCode with the Haskell extension (or your favorite editor), and you’re ready.


GHCup – the main Haskell installer.

GHC (Glasgow Haskell Compiler) – the compiler.

Cabal – a Haskell build tool.

Stack – alternative Haskell build tool (based on snapshots).

HLS (Haskell Language Server) – Haskell LSP support.


And this is precisely what we’re going to do.

Note that I’m super lazy; this is almost the setup I’m using. The only configuration I ever do is install another font. But you can take it way further than that.

Installation

We can get all we need with one single tool, GHCup. It manages the main Haskell tools: GHC, Cabal, Stack, and HLS. We don’t need to install or manage any of these by hand.


💡 Fun fact: GHCup has nothing to do with cups.


After you install GHCup for the first time, you should have a working Haskell stack on your machine.

You can use the command line interface to upgrade/update the tools; for example, install the recommended version of the language server (hls):

ghcup install hls
Enter fullscreen mode Exit fullscreen mode

But you can also use the tui (text-based user interface):

ghcup tui
Enter fullscreen mode Exit fullscreen mode

ghcup-tui

You can see from the screenshot which hls versions I have installed and that I also have multiple versions of ghc installed for different projects. And it’s super easy to jump between the versions. I don’t even think about it.

Build tools

There are two main build tools in Haskell: Cabal and Stack. Over the years, their popularity keeps shiftings, and their functionality keeps converging. If you're getting started, you can use either one.

One difference is that Stack uses the curated set of packages by default, while it must be configured in Cabal.

Stackage is a community project that curates these sets and bundles the dependencies known to build together, avoiding any version conflict problems. Which is very appealing. Especially if you have ever experienced ClassNotFoundException at runtime, had to shovel yourself out of the conflicting guava dependencies in Java, or something along these lines.


💡 PureScript has a similar project, called Registry.


stack-overview

Because I’m lazy and want to illustrate it quickly, I’ll show you Stack.

We can initialize and run a project (named, for example, dry-run) with these commands:

stack new dry-run
cd dry-run
stack run
Enter fullscreen mode Exit fullscreen mode

Which will probably print:

someFunc
Enter fullscreen mode Exit fullscreen mode

🙂 You can imagine that it says: “Hello, World.”

Now, let’s try to change the code.

IDE

We only need HLS (which we already have after installing GHCup) and VSCode with the Haskell extension.

hls-extension

And now we have a fully working IDE.


💡 It doesn’t have to be VSCode! You can use your favorite editor with HLS.


HLS provides go-to-definitions, autocompletion, and all the other stuff, which we can use to find the someFunc, change it, and print something else:

hls-goto

hls-print

someFunc :: IO ()
someFunc = print 42
Enter fullscreen mode Exit fullscreen mode

And then, we can run the project via the terminal.

Now, let’s add a dependency. For example, let’s add aeson – a library for working with JSON. We need to extend the dependencies list in the package.yaml:

dependencies:
- base >= 4.7 && < 5
- aeson
Enter fullscreen mode Exit fullscreen mode

And we don’t need to worry about the library version, the resolver handles the versions for us – it chooses a specific Stackage snapshot. We can check it in the stack.yaml:

resolver:
  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/11.yaml
Enter fullscreen mode Exit fullscreen mode

And the cool part: if we want to add and use another library, which is also an aeson dependency, for instance, text, we know that the version we utilize in the project is compatible with the version that is required for aeson.

As an illustration, we can use this library to encode a list as JSON. Note that we can use auto-import.

import Data.Aeson (encode)

someFunc :: IO ()
someFunc = print (encode ["Hello", "World"])

-- Prints: "[\"Hello\",\"World\"]"
Enter fullscreen mode Exit fullscreen mode

Hoogle

Have you ever forgotten a name of a function? Or how many minutes have you spent scrolling through the autocomplete suggestion list, searching for a method that fits? Or how often do you have to jump between library docs to find that data structure you need?

What if there was a type-aware search engine that you could ask?

Well, we have this tool in Haskell, and it’s called Hoogle. We can use it to search Haskell libraries by name and type signature.


💡 We also have such tool in PureScript, which is called Pursuit.


Okay, are you ready? Let’s do a couple of searches.

Search for a text

Sometimes, I have to use a function to add a value between the elements of the list. For example, add a comma between the list of words. But I struggle to remember its name – it’s either intersperse, intercalate, or inter- whatever.

I can use Hoogle to search for it:

inter
Enter fullscreen mode Exit fullscreen mode

It shows the type signatures and the docs, so I remember it was intersperse once again.

hoogle-text-inter

It’s right there, closer to the bottom:

intersperse :: a -> [a] -> [a]
Enter fullscreen mode Exit fullscreen mode

Okay, nothing crazy; it's as impressive as autocomplete. But!

Search for a type

But we can also search for a type right away.

Let’s start from scratch. What do we need from this function? We need to pass an element and a list (the types of the old and new elements should be the same), and the result should be a new list. So, we can search for it:

element -> [element] -> [element]
Enter fullscreen mode Exit fullscreen mode

It’s right here, on the top:

hoogle-type-intersperse

We can use simpler types to search:

a -> [a] -> [a]
Enter fullscreen mode Exit fullscreen mode

It doesn’t change the result:

hoogle-type-intersperse-a

Or, imagine we’re looking for a function that checks if the element exists in the list. This time, we change the return type to boolean:

a -> [a] -> Bool
Enter fullscreen mode Exit fullscreen mode

And get something like this:

hoogle-type

Which gives us elem and it’s negative twin notElem.

Note that we used a polymorphic type a because we wanted a function that works for any list, but we can search for a more specific type as well:

Int -> [Int] -> Bool
Enter fullscreen mode Exit fullscreen mode

In this case, Hoogle first suggests more specific functions and then generic ones like elem.

hoogle-type

And it works with the whole stackage set (or even beyond it) – we can use it whenever we’re stuck looking for a suitable function. If this isn’t cool, I don’t know what is.


💡 Note: You can also install Hoogle locally – run searches on a command line or in a browser, and even hook it up to your editor.


Conclusion

So, yeah, there is no “Tooling Issue” in Haskell. You install one tool and one editor and have all the autocompletes, auto-imports, goto-definitions, etc.

Also, I want to thank everyone who is working on the tooling. You’re the real heroes.

The tools are improving daily, and I’m curious if this walkthrough will age well.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player