Haskell workflow

Workflow

Unlike Python, Ruby, JavaScript, Lua, and other interpreted languages, Haskell is compiled ahead-of-time, directly to native machine code. The compiler (GHC) is remarkably good at optimization and generating efficient executables.

💡 Although Haskell can be both interpreted and compiled, as there are both interpreters (ghci) and compilers (ghc) available for Haskell.

For our workflow, we are going to look into GHCI (GHCi is GHC’s interactive environment, in which Haskell expressions can be interactively evaluated and programs can be interpreted), because we want to have a good Developer Experience:

  • Automatic execution of the source-code as we go
  • Quicker iterations and feedback

Alternatively, we’d have to manually compile everytime we make a code change, which would make the whole development experience unpleasant! Frustration with slow compile times and loose precious feedback loops in the workflow!

That’s where GHCId comes into play!

Either “GHCi as a daemon” or “GHC + a bit of an IDE”. To a first approximation, it opens ghci and runs :reload whenever your source code changes, formatting the output to fit a fixed height console. Unlike other Haskell development tools, ghcid is intended to be incredibly simple. In particular, it doesn’t integrate with any editors, doesn’t provide access to the ghci it starts, doesn’t depend on GHC the library and doesn’t start web servers.

So, we’ll install GHCId to our stack

stack install ghcid

It’ll be added to stack but also to your local path (~/.local/bin/ghcid). From then on, you can run it either by calling it in stack:

stack exec ghcid <HASKELL-FILENAME>

Or, since you have it in your local PATH

ghcid <HASKELL-FILENAME>

Once you run the command, the ghcid application will persist in the terminal session, in other words as a foreground process. Effectively meaning that it keeps watching your file and executes automatically on change, so you do not have to worry about and just look at the output!

For this reason, you should open a separate terminal window, just for monitoring your source-code changes, as you go!

Is Stack a sandbox?#

It’s more than a sandbox, the real point of stack is integration with stackage, which is a curated collection of packages known to work together with a specific ghc version. Meaning that if you stick to stackage for everything then it all “just works”.

Although, things start to fall apart as soon as you need something outside of stackage (not counting on your own local packages, which presumably you will write to work with the same stackage snapshot).

💡 If you stack install a executable (ghcid) it gets added to your users path and you can use it. This might sound weird, because that stack works in a sort of sandbox, but if all you need is an executable (like ghcid or brittany) then it’s pretty silly to add its whole build plan to yours, therefore the executable is “exported” so that you can use it wherever!

Stack holds all its builds inside itself, so if you just run ghcid it probably won’t be able to build your package. That’s what “stack exec” is for, it’ll expose the package database stack uses to build your program(s).

Part of the sandboxing aspect of stack (and cabal), stack and cabal take roughly opposite approaches to what and how they sandbox, but both do sandbooxing so you don’t run into problems with multiple projects that have different dependency requirements.

References

https://wiki.haskell.org/GHC/GHCi

https://docs.haskellstack.org/en/stable/ghci/

comments powered by Disqus