Cabal Quickstart with HLS Pains

After my question about what’s changed in Haskell, I’m trying the new cabal for the first time in years. I’m an experienced Haskeller, but I’ve always used stack, so my experience may be comparable to first-time users.

I’m following the Cabal Quickstart and I’m running into lots of issues.

  1. First, I had ghcup installed already, so when I went to install all the latest goodies, I ran into some issues, including a mysterious segfault, due to not realizing I needed to “set” ghcup to the latest. Then once I did, lots of other problems because I had run cabal init before setting it to the latest. Confusing, but that’s on me, and most users won’t have old installs.

  2. Ok, I have a new project. I follow the interactive prompts to make an “executable” project. cabal run works! Now I load the project into vscode and HLS creates some popups, but then does… nothing. I can create errors and it doesn’t detect them. Weird. I restart HLS and works once, but won’t update.

  3. Without having figured out how to get HLS to update automatically, I try adding a second file: Test.hs, and HLS gives me the following error. I’m confused, I google it, and it isn’t immediately obvious what the problem is.

Multi Cradle: No prefixes matched
pwd: /Users/sean/Documents/code/apocalypse-generator/mcgen
filepath: /Users/sean/Documents/code/apocalypse-generator/mcgen/app/Test.hs
prefixes:
("app/Main.hs",Cabal {component = Just "mcgen:exe:mcgen"})
  1. So I try cabal run again for kicks, and now the error makes sense. I have to add every source file to my .cabal file? That’s unintuitive and painful. I used to use stack with hpack integration and it was automatic.
<no location info>: warning: [GHC-32850] [-Wmissing-home-modules]
    These modules are needed for compilation but not listed in your .cabal file's other-modules for ‘main’ :
        Test

Adding Test to other-modules and restarting HLS makes it start updating as expected.

What’s the best way to create a cabal project that automatically includes source files in other-modules? I’m not publishing a library so I don’t need fine-grained control.

How can I help make this experience better for first-time users? I think most non-haskell programmers would get stuck and give up experiencing the above.

Thanks!

8 Likes

Thanks very much for this experience report! I think experience reports like this, when someone is just starting to use a corner of the ecosystem, are essential for filing down rough edges and improving ergonomics.

Unfortunately I can’t help with the cabal or ghcup stuff. I was, however, surprised that Googling GHC-32850 doesn’t turn up an errors.haskell.org page so I filed an issue.

3 Likes

This sounds strange and unfortunate. Can you elaborate? A segfault in what program? In ghcup, cabal or ghc? ghcup itself is not “set”, so perhaps you mean ‘set “ghc” to the latest’? In which case was an older version of ghc segfaulting? Which version and what platform are you on?

I opened an issue about that two months ago: More flexible prefix matching · Issue #3585 · haskell/haskell-language-server · GitHub

1 Like

I mean that when you hit “i” in ghcup tui, it installs the executable, but doesn’t make it active, until you hit “s” for set. I didn’t realize this. I thought installing would switch the version

I doubt I could reproduce it now, but I think what I did was:

  1. cabal init. this didn’t run interactively, it must have been an old version.
  2. upgrade ghc via ghcup
  3. cabal run. It exited with a segfault and no useful information.

I’m not 100% sure that was the order but it was something like that.

1 Like

Wow, that is bad! But if it’s an old version of cabal I guess there’s nothing to do about it now.

Notice if you already have an old version of cabal, stack or ghc (including ghc version installed with stack in the past) they will likely conflict with versions installed by ghcup. I’d suggest you delete any prior-to-ghcup haskell tool

Yes. You do have to add all source files manually to your .cabal file. And yes, it is unintuitive and painful.

Honestly, I don’t know if I prefer cabal's approach or stack's. Having a very static and explicit description of your package is verbose, but there is kind of a point to it. Other tool ecosystems (for example python and pylance) rely on conventions to include files in their packages (for example adding a __init__.py in the folder). From my experience that leads to some sort of caos in which scripting files are included as part of the libraries and multi project packages aren’t well defined, plus pycharm follows different convention than pylance so it is difficult to share projects.

1 Like

The reasoning behind this is that lots of people use different GHC versions in different projects and just because they install, say, a newer GHC, doesn’t necessarily mean they want it as default.

The TUI could surely be more prominent about it, but it also tries to be lean and not get in your way with popups and dialogs.

I think a common way to handle this in user interfaces is with an initial “introductory mode” that gives hints as you go and then is turned off. That requires some design and probably a lot more TUI code, so I don’t know when/if this is happening, unless someone writes a patch for free.

5 Likes

I have a strong preference for some kind of implicit inclusion of files. Enough that I will switch to stack if I can’t figure it out. I suspect other people are like me. I’m trying to reflect and figure out why it bothers me so much. I think it’s because when I am creating new files, I’m usually in the middle of flow, solving some problem, and it interrupts that? Maybe also because it’s really uninuitive for people coming from other languages, and I want to decrease the friction for adopting Haskell with people I work with.

I too have experienced problems in Python’s generation of languages. But I’ve never had a problem in more recent languages (Rust, Node.JS, Swift, etc)

I think when the language has an opinionated convention that’s enforced by a compiler it’s hard to go wrong.

4 Likes

Oh I’m misunderstanding something… what does it mean for a GHC version to be “default?” - Does ghcup simply switch the globally available binary? Or does it do something fancier than that? Switching to the most recently installed binary doesn’t seem as strong as making in a default. I’m installing it because I need to use it right then.

On that same note, why don’t projects specify which version they expect, and ghcup switch automatically when you enter the directory, or compile something? This is another thing that stack did that made sense to me.

That just means what you get when you type ghc in the terminal or run cabal build without any specific project configuration.

That said, you can tell cabal in two ways which ghc version to use exactly, in which case the ghc binary doesn’t matter:

  1. cabal build -w ghc-9.2.8
  2. the with-compiler directive in cabal.project files: 7. cabal.project Reference — Cabal 3.10.1.0 User's Guide

They can, as described above.

There’s no need to switch if the with-compiler directive is used. But yes, cabal won’t install a missing GHC for you. That might be possible in the future, through shell hooks: shell hooks for augmenting how cabal-install does various actions? · Issue #7394 · haskell/cabal · GitHub

2 Likes

And to elaborate, specifically through the link at $HOME/.ghcup/bin/ghc.

This is great, thanks for the info!

Well… one could say that the opinionated Haskell convention is to explicitly list all source files. Anyway, probably I agree with you that It should be enough if you just point to the folder containing all source files, instead of listing them one by one… I guess It just doesn’t bother that too much :sweat_smile:

It’s somewhat ambiguous. At work we have modules from different packages all mixed together in the same source tree. It makes things fantastically easy to find!

In principle a build tool could support both styles, I suppose.

The idea is that the job of doing this mundane thing is more of an editor/IDE feature and not really business of a build tool (which prefers to be correct rather than guessing a users intention).

2 Likes

I agree, I think the best UX would be that HLS shows the user a dialog: “Module … has not been added to your cabal package yet, do you want to add it? Yes / No / Always”, instead of the “no prefixes matched” message.

4 Likes

Yeah that particular message is particularly baffling.

1 Like

Wanting the IDE to take care of it is fair.

I have a week before I start my job, so I have time to fix this.

The most pressing thing to fix is probably adding a Better error message in HLS? It should say you forgot to add the file to the cabal file

After that I’m not sure. Is HLS interactive like that? The easiest workaround is probably to add an hpack plugin to visual studio code that automatically runs whenever you add or remove files.

Thoughts?

1 Like

I just opened an issue with haskell-language-server about updating the error message

1 Like