Developing an application from scratch (Haskell Unfolder #46)

Will be streamed live today, 2025-07-09, at 1830 UTC.

Abstract:
In this episode targeted at beginners, we show the end-to-end application development process, starting from an empty directory. We’ll consider package configuration, taking advantage of editor integration, how to deal with dependencies, organizing code into modules, and parsing command line arguments. We will use this to write a simple but useful application.

10 Likes

Thanks! for the video.

You chose Cabal (the tool). I should declare my interest: I am the active maintainer of Stack. That declared, beginners might also like to check out the Haskell Tool Stack (Stack, for short). It has a getting started tutorial at:

I am particularly interested in feedback on Stack from beginners because I was, not so long ago, one myself and I’ve been trying to focus Stack’s primary goal - to be easy to use - at beginners.

8 Likes

Thank you Edsko and Andres. And thank you Mike. I have one immediate reaction: starting with cabal is much too complicated for a beginner (since that’s what Mike asks about).

I am not a beginner – in the sense I’ve been programming in Haskell for ~15 years. OTOH I’m more like a beginner in that I’m a hobby programmer/ex-professional in commercial languages. I’m creating programs for my own entertainment, not to share with others, not to be long-lived/upgraded through many versions of the compiler or base packages. It also might be relevant I’m a Windows user; I’m allergic to command lines; I much prefer point-and-click.

So my use case is perhaps more like a student on an introductory semester to functional programming. I’ll be producing a series of self-contained applications. I’ll need some utilities – which I can grab through imports at the top of my modules.

Edsko starts by saying there’s “nothing there”. But that’s not true. There’s a compiler; there’s the Prelude; and there’s a whole bunch of utilities in Base. Does a beginner need more than that? Perhaps my course provides some for me to download. As the Stack intro says

GHC comes with the libraries of certain Haskell packages (known as boot packages ) already installed in its global database of installed libraries. These include the library of the package base, which is a dependency of almost all other packages, and …

For many years, GHC (or Hugs) +base was all I needed. Later I could use Hoogle to search for stuff, click through to Hackage, point-and-click to download and unpack the .tar.

I don’t need a licence (why does Edsko even talk about that?). I don’t need versioning. I don’t have scarey-sounding things called ‘dependencies’; I just create a .hs file and put some imports.

(I think you should also mention that cabal is both a file/directory format, with an internal language; and a toolset that uses that format. But there are other toolsets that use that format, like Stack. It’s also a little confusing from the name whether ‘Stackage’ is intimately related to Stack. I’ve never gotten anything from Stackage; why would I need to?)

Now, I’m sure this would all be much different if I were employed to program in Haskell/collaborate on a large application/support software artefacts that were long-lived. In that case, I’d expect the programming shop to have a whole bunch of policies and procedures for installing stuff and hosting it on servers, check-out/check-in/code reviews/etc. That’ll all be after I’ve got enthusiastic about Haskell.

For my situation, I have several times considered adopting cabal or Stack (and then there’s Nix, at 9:30). Each time I’ve been scared off by the complexity. You’ve scared me again.

Is it possible to run cabal or Stack backwards, so to speak:

  • First create a fresh directory with a .hs module Main, declare main.
  • Add some imports to supply methods/decls.
  • then ask cabal to build its project around that.

Similarly, could the tutorial have more followed that plan?

  • As you add more exotic libraries (outside of Base), managing the dependencies gets tricky;
  • the scenario motivates why you’d need tooling; so
  • then introduce cabal.

BTW perhaps why I’m reluctant to get locked in to a toolset is that I run a lot of text-driven developer-like applications: theorem prover, linked spreadsheets, databases, macros, … They don’t seem to need much dependency management/versioning/packaging.

Thanks for your perspective. I’m well aware that this is an area where people have very different experiences and viewpoints, and that not everyone has the same preferences.

I think doing Haskell without involving any .cabal files and using neither stack nor cabal is certainly possible, but in my personal view not worth it. As soon as you need any external dependencies, you have to do weird things that are no less complex than setting up a proper package, plus then you’ll still be in a non-standard situation which makes your package harder to share and distribute. And if you try to avoid external dependencies, then you’re locking yourself out of lots of great libraries, and I personally would like base to be smaller rather than larger.

Whether to use cabal or stack specifically, I have no strong opinion on. I think both are fine for beginners. Stack seems to generally have the slightly better documentation and perhaps the slightly nicer user interface as well, but I’ve seen students struggling with both over the years, and also things are improving all the time. In general, I think they both work reasonably well, and they both have the potential to yet be massively better than they are. In the episode we picked one of the two primarily because we didn’t want to make the episode about the choice and the history, and because cabal is what both Edsko and I primarily use in practice.

Just to share one more viewpoint. What I personally do when I start a new package is to not even use cabal init, but I typically hand-write or copy a cabal file more or less like this:

cabal-version: 3.0
name: my-example
version: 1
build-type: Simple

executable my-example
  default-language: GHC2021
  build-depends: base
  main-is: MyExample.hs

And that’s it. As you say, no LICENSE, no fields I don’t need. Wouldn’t be accepted by Hackage, but in many cases a potential upload is far away anyway. I think the cabal init approach is probably nevertheless better because it has potentially an interactive mode, you don’t have to remember the magic lines that you absolutely need, and it can generate comments that explain what everything in a cabal file is in principle about.

5 Likes

You make a number of points that I agree with:

  • on a user being able to do a lot of interesting things just with what comes with GHC (including GHCi), agreed. I’ll tweak Stack’s brief introduction to the Haskell landscape to acknowledge that (EDIT: now done);

  • on being a Windows user, so am I. My goal for Stack is that Windows users are also ‘first class citizens’;

  • on the problem of ‘complexity’, agreed. I call it the ‘Swiss Army knife’ problem. A new user only needs to know about the main blade; how to tuck everything else away until it is needed (if it ever is)? You don’t want the user to experience (and be scared off by) this (credit: National Museum of American History):

    image

  • on the Stackage/Stack relationship, the history is before my time but I understand that Stackage (‘Stable Hackage’) came first (back when Hackage was not always ‘stable’), and Stack started life as an in-house tool of consultancy FP Complete to make use of Stackage. The projects are distinct but, these days, Stackage makes use of Stack behind the scenes and Stack is focussed on making use of lists of package versions that are known, by testing, to work well together and with a specified version of GHC (‘snapshots’);

  • on creating a Stack project from existing files (as opposed to from an existing Cabal package), Stack does not do that. I think it would have to be quite clever to guess what the user wanted to do. However, if you command stack new my-package it will set up something small with sensible defaults (and fetch GHC, MSYS2 etc if needed). No ‘questionnaire’ in the case of Stack. (Later on, Stack provides templating for project set up, so you can configure stack new my-package my-project-template so that everything is ‘just so’. But with configurability comes the complexity of understanding available choices and making them …)

3 Likes

As a beginner I think its an horrendous experience to choose which build tool to use.
lets say Python,or Node, so many alternatives.
I like the approach of Go, yeah the compiler is the build too.
Same is in Clojure ecosystem, all of them used lein now half projects use deps.edn v/s half use the other.

Why can’t Haskell have one build tool with a simple interface ?!

3 Likes

Your final question has two key elements: (1) ‘single’ and (2) ‘simple’. Fundamentally, I think the answer is that the Haskell community is a very broad church, different people want different things from a ‘build tool’, and a single tool that is configurable to meet their different wants is no longer simple.

2 Likes

Yeah. The Get Started page recommends installing both Cabal and Stack; presumably expecting you’ll defer the choice. Oh, but first you need GHCUp, which seems to be another toolset. (And that does at least cater for those who “don’t like curl | sh” – in very small print.)

Yes sure. And a broad church has many doors and aisles. GHC seems to lack a big friendly sign saying ‘newbies please start here’. (Also, as I understand it, you have to choose Cabal vs Stack at an early stage, then you’re stuck with it.)

Similarly I can hand-write or copy a .hs – specifically drag-and-drop (in “interactive mode”) a stub that starts with my usual LANGUAGE options and imports.

The video started with some complex command-line stuff, and a discussion of options. Not with any Haskell code at all. So you ground our noses into the tool. Then I think better to start the video with the cabal stuff already done – indeed start already within the editor with some Haskell code showing; come back later to explain how you got there.

Ok. So same as drag’n’drop, but with extra opportunities for typos.

I think it just has to parse the beginning of the .hs, up to the module decl + imports. (I think these days GHC has an ability to spit out its parse tree?)

1 Like

Not necessarily. I have been working on several projects that can be built using both. Switching from one to the other is in principle no major effort (except that you need lots of disk space and some time to wait for the rebuild).

Fair, but I disagree. First of all, I said we didn’t want to make the video about the choice. We did want to make a video about going all the way from an empty directory to a “working” and “proper” Haskell application. To me, this includes setting up a proper workflow with either cabal or stack (or nix). .cabal package descriptions are shared among all these tools, so having some knowledge that they exist and what they’re doing approximately is definitely useful when you’re working in the Haskell ecosystem.

There are lots of videos and blog post out there that focus on some cool program and disregard all the infrastructure and tooling aspects completely. This is fine, of course. You don’t want to talk about it every time. But the point of this episode is to show everything, and not omit any important steps. I think that as a community, we are spending too little, not too much time, explaining the more mundane aspects of building software with Haskell.

You make it sound like that’s equivalent, but imports don’t contain any information about the packages these are coming from.

7 Likes

Thanks a lot for sharing your experience!

I understand that as a beginner, the tooling landscape of Haskell is massively confusing, and I wish it wasn’t. Haskell is by no means unique in this (think e.g. Javascript), but I don’t mean to use this as an excuse. However, Haskell is a consensus-driven open source community. You cannot just make existing tools “go away”, and nobody can or should unilaterally dictate what everyone should use.

Historically, Stack was created to address concrete pain points people had with cabal at the time, and it follows a somewhat different model. Since the publication of Stack, cabal has changed quite a bit. Many of the original pain points are gone. I think one can probably say that to some extent, the competition between Stack and cabal has helped both tools to become better over time. But cabal still works a bit differently from Stack, so among experienced users, some prefer one, some prefer the other, and that’s valid.

The fact that both are used in practice in my opinion makes it necessary that an installer such as GHCup can install both, as it currently does. Otherwise, if the one GitHub project that sparks your motivation to enter the Haskell world happens to use the “wrong” tool, you’re already at a massive disadvantage.

So the remaining question is advice for beginners. I agree that most official sources shy away from making a very clear recommendation because it is unclear whether there’s consensus in the community what that recommendation should be. I find it easier to give such a recommendation in a Well-Typed video or speaking for myself than as a representative of the Haskell Foundation, for example. Nevertheless, the official text on haskell.org says things that are in line with my experience. It recommends installing both (I agree), it acknowledges that cabal seems to be the current majority choice (I agree), and it says that otherwise, you can just follow the recommendations of whatever tutorial or book you’re using.

Now on that final point, it might be worth taking a stronger position rather than deferring to random other sources, in particular as quite a few Haskell books and tutorials shy away from the tooling question completely and focus just on the language. Perhaps it is time to revisit this point once more. But it depends on whether there’s sufficient community consensus for this.

8 Likes

I should have mentioned stack, that’s an omission. I don’t use it personally, so I just didn’t think about it while I was focused on the episode. I have added a pinned comment to the video to mention that stack is alternative that is well worth exploring.

3 Likes

so the half the hackage packages will be stack based and half of em won’t.
This is a major reason many new comers struggle to make project.
everything is gold and roses untill u are playing with GHC and GHCI, as soon as HLS,Cabal/Stack comes, things start becoming slow, unpredictable and etc.

1 Like

Thanks for your reply!
I really like the videos you make, cause Haskell has many books but very less videos. and some peopel prefer videos

Some things I don’t like about Cabal is that you just can’t add a library like npm i or yarn add
so u manually have to add it in .cabal file.

Also, its a pain that as u change ur .cabal file, the HLS freeezes. It cannot index the new package and it shows error.

At this point I stopped using HLS, I am happy to use Hoogle, GHC and GHCI, they always work and work awesome.

In Haskell Community I feel, the mindset is of exploring rather than making it pragmatic, and yeah thats a great spirit, u can discover new ideas, the language gives u freedom, but then when it comes to a pragmatic choice, its all dark .

Consider formatter, I wish there ghc had a format command like Go.

The world took inspiration from Node for packaging and build, but Go was right there with the simplest and most easy to use interface.

But Haskell has grown quite a lot, I wish the new resources (books/blog) put more focus on projects rather than just GHCI, because u need to install packages at some point.

None of the resources I did like Cis1940 or LYAH, have a clue about GHC Extensions, and yes thats right because they given an introduction, but where can someone refer to learn stuff like that ?!

1 Like

With Cabal external commands feature, you can!

Install cabal-add and then you can type (with cabal ≥ 3.12):

cabal add mydep
6 Likes

On packages on Hackage being ‘Stack-based’ or otherwise, that is a misconception: a package on Hackage is ‘just a package’. Cabal (the tool) and Stack are both making use of all the same Hackage packages.

Haskell beginners are all sorts. However, if a beginner today was worried that if they, initially, choose one of Cabal (the tool) or Stack as a build tool they risk making a fundamentally wrong choice that will leave them ‘stuck’, I would advise them - emphatically - that is not the case.

It won’t surprise you that the Stack project recommends Stack to a new user who has no experience with other tools:

However, the project does not suggest that, today, Cabal (the tool) is, in some sense, a ‘wrong’ choice.

Choosing to start with either, with support, they will soon learn how the parts of a Haskell project come together. Having learnt that, they can then make an informed choice about whether to stay with what they have or use (or also use) the alternative.

‘With support’ above is key. I like to think that any beginner can ask any question here and they will find help. My only tip is that the better the quality of the question, the more helpful the answers. I also hope that Stack’s online documentation is accessible for all sorts of beginners. If it is not, I aim to fix that.

6 Likes

I guess there might be two senses of ‘beginner’ at play here:

  • New to Haskell, but already a professional programmer in other languages, so familiar with tooling/indeed expecting a mature language would have tooling. Then a ‘from scratch’ presentation should at least mention packaging/dependencies/versioning, to give Haskell ‘street cred’.
  • New to programming in general/maybe still at the stage of kicking the tyres to decide what language to major on. Then probably with only a vague idea of what is packaging/etc, and no motivation as to why it’s useful.

From what I can see, packaging/versioning/dependency/hell just is complex in general; it’s not specific to Cabal nor Stack, and Nix seems to be a complete monster.

I think a new-to-programming beginner might very reasonably be asking a bunch of questions through Edsko’s first three or four minutes:

  • What’s the difference between a ‘package’ compared to a ‘program’?
  • Are those package instructions part of Haskell-the-language?
  • Is there anything specific to functional programming in that init stuff?

I think more context-setting right at the start would be helpful: this video isn’t focussing just on the language, but also on the workflow to develop an application; so showing some tools outside of ‘just’ the language.

but why is such a useful command not in the cabal bin itself ?!

1 Like

If you are referring to “it can generate comments that explain what everything in a cabal file is”, cabal init does that for you!

If by any chance you meant cabal add, there is a ticket to adopt cabal-add into cabal.

7 Likes

You ask about how to learn about GHC extensions to the Haskell language.

You’ll get a better answer to that if asked as a separate Topic (not least, you can supply the context in which it arises) - checking that any existing Topic has not met your needs, for example (from August 2023):

In short:

2 Likes