To elaborate on that point: I found that in some circumstances (Template Haskell), HLS fell over if there was no GHC on the PATH. Running in the Stack environment ensures that GHC is on the PATH.
That’s still a bug and shouldn’t be necessary
I will see if it still applies with current HLS: my current behaviours reflect solutions to past experiences, and HLS may well have moved on in the interim.
EDIT: It still seems to be a current problem with GHCup-supplied HLS-2.9.0.1. Outside of the Stack environment (no ‘system’ GHC on PATH), HLS fails with:
[{
"resource": "/D:/Users/mike/Code/GitHub/commercialhaskell/stack/src/Stack/Constants.hs",
"owner": "Haskell (stack)",
"severity": 8,
"message": <see below>
"source": "typecheck",
"startLineNumber": 618,
"startColumn": 3,
"endLineNumber": 618,
"endColumn": 76
}]
Message extracted from above:
• Exception when trying to run compile-time code:
ghc: readCreateProcess: does not exist (No such file or directory)
Code: (TH.runIO (readProcess \"ghc\" [\"--show-options\"] \"\")
>>= TH.lift . lines)
• In the untyped splice:
$(TH.runIO (readProcess \"ghc\" [\"--show-options\"] \"\") >>= TH.lift
. lines)
I definitely agree with this. And to be honest, in my dabbling with Cabal I’ve found that for everything other than HLS integration, I still prefer using Stack. But HLS integration is really important, especially for a new user.
For sure… for my own personal use, I’ve been using Stack and dealing with the workarounds. I think for non-beginners who understand the trade-offs, it’s fine just to dive in, knowing you’re going to have to futz around, figure out how to get past certain HLS/Stack annoyances.
For beginners, though, the experience is pretty bad. And the above issues, “well-documented” as they are for folks who have spent a bunch of time on these forums or searching through HLS github issues, are not at all obvious. They manifest as 1) seemingly inexplicable errors at the top of a file, or 2) files that inexplicably seem to be “behind” on your latest code changes. Again, for those with context, it’s not hard to do the dance of clearing caches, restarting servers, etc. For a beginner, that’s just “Haskell seems broken, what do I do”.
Speaking as a somewhat-recent Haskell beginner, I can say: I wanted a set of tools that integrated with each other in non-surprising ways
If I could go back two years and give myself advice, it would be:
- "Use Stack, but here are a list of specific issues you’re going to run into if you use HLS (which, as a beginner, of course you’re going to use HLS), how those issues are going to manifest, and exactly what you need to do to fix them. Or, alternatively…
- Use Cabal. At least until you learn your way around enough to do otherwise."
If Stack is going to be recommended for new users, I think the Stack/HLS caveats should be called out loudly on the Haskell downloads page, the Stack documentation, and more loudly that they are already on the HLS documentation. People shouldn’t have to get to the point of starting a Stack project, getting elbows-deep into development, hitting issues, and navigating to a “troubleshooting” page to finally learn about these caveats.
Also, if there are specific steps that can always fix the issues, I feel like they should be written down and basically shouted from the rooftops. (Or even built into the tooling. The VS Code plugin could have a “Fix Stack by clearing caches, re-building, and restarting the server” button .)
As it stands now, from the perspective of a beginner, it often feels like: “Well, here are some things you can try. Good luck…?”
Which project/team do you think should do that testing and documentation work, ideally ? Stack / HLS / Haskell Foundation / Everyone ?
Thanks for advocating for [new] users. I agree that identifying and documenting the current caveats and workarounds precisely will be a big help.
i use nix + cabal-install and my experience is that if i am not either trying to use a newer ghc than stackage-lts or a package with very few downloads, i tend to have 0 problems. Previously i used only cabal-install on archlinux and i don’t remember any issues besides the archlinux specific ones.
if stack is so flaky, i don’t know if hpack and a slightly better UX is worth it.
Ultimately, HLS supporting Stack better is a shared goal/shared problem of the HLS project and the Stack project.
However, the Stack project may look to the Cabal project, as Stack uses Cabal (the library) to build. That is, I understand that HLS would like to know from Stack what is passed to GHC to build a specific module but Stack does not know that directly; Stack passes commands to Cabal (the library) to build packages.
So, it seems to me, for Stack to know that information, Cabal (the library) has to tell Stack that information. Perhaps there is a Cabal command that does that, but I can’t see that it is documented at 5. Setup.hs Commands — Cabal 3.12.1.0 User's Guide.
(Cabal (the tool) has an --enable-build-info
flag, but I can’t see that Cabal (the library) has something similar. EDIT: Correction: there is an configure --enable-build-info
flag, documented only in-app.)
Stack does have a page of its online documentation on using Stack and VS Code (and its HLS-powered ‘Haskell’ extension): Stack and Visual Studio Code - The Haskell Tool Stack If people think there is something that could be usefully added to that page, please raise an issue at Stack’s repository.
HLS’s ‘needs a stack build
to work’ problem is documented on that page as a ‘tip’. I had not appreciated that it had been identified in HLS’s documentation as a concrete problem.
Of course! I think it’s easy (and totally natural) for experienced users with a lot of context to forget the mindset of a new user with zero context. That’s why I wanted to write this stuff down before I fully cross that threshold
I think it’d have to be an overlapping effort. But take my suggestions with a grain of salt! I don’t fully understand the various teams, foundations, and companies involved. That said, here are some concrete changes that would have helped me as a new user:
-
Clarify the toolchain options on the main Haskell downloads page. “Prefer” one build tool over the other by default, and clarify that the two tools are overlapping. (Right now, the implication is that both are “required”, by way of HLS being the only tool marked “optional”.)
-
Be similarly opinionated on the main getting started page. This guide tells you to install both (probably good advice), but gives you no guidance one which to start with for your own projects (or why).
-
The GHCup getting started guide is more successful in this way, I think. It picks cabal and gets you started with it. This guide should probably be linked from the main haskell.org page… it’s great!
-
However the GHCup install page is less successful – to clarify the Stack/Cabal situation, it links to a gist which makes an attempt to be opinionated, but which makes no mention of the Stack/HLS caveats. It’s also filled with comments giving conflicting advice, which certainly comes across as confusing to a newcomer.
-
The HLS troubleshooting page should probably contain concrete next steps for a user, e.g. “You have two options 1) Continue using Stack and do [these specific workarounds], or 2) Migrate your project to Cabal. Here are docs and/or tooling to accomplish that.” It would be helpful to clarify that these are not “temporary” problems, and that these issues have existed for years now.
-
Mention the HLS/Stack issues in any/every place where the “Cabal vs. Stack” question is raised to new users. A user should never get to the point of
stack new
without being aware of these caveats, IMO. I think this should be loudly called out: 1) on the Haskell downloads page (if Stack is still recommended), 2) in the GHCup docs, 2) in the Stack docs, and 3) in the HLS docs (not just in the troubleshooting section). And, for better or worse, the issue manifests to users as an HLS problem (“HLS is broken in my tests but works in my main project”, e.g.), so I think HLS will have to bear some responsibility for documenting the potential solution(s).
I’d certainly be happy to file some relevant issues, open doc PRs, etc. I just don’t want to assume that my naive “here’s how I think things should be!” viewpoint is shared by everybody
As for fixing the problem itself: from what I understand it’s a shared responsibility of Stack and HLS. Though from what I gather from this issue, the ball is somewhat in Stack’s court at the moment? But don’t quote me on that!
HLS is ‘optional’, in the sense that you don’t really need it to develop Haskell projects - but it is very useful. Some people have argued in other discussions here that you don’t really need Stack or Cabal (the tool) either, to start out, but I think you need at least one of them once you move beyond evaluating expressions using GHCi.
The problem with an ‘opinionated’ getting started page, is … opinions differ. The respective strengths and weakness of Stack and Cabal (the tool) today for different purposes on different platforms are not easily summed up with ‘one-line advice’. If you are developing on Windows with Haskell packages that use C libraries, it can be useful that Stack supplies MSYS2, for example. If you want to use the Hpack package description format with Cabal (the tool), it requires a standalone hpack
executable. (I say ‘today’ because existing guides can be out of date.)
GHCup is, I think, largely agnostic as between Stack and Cabal (the tool). Stack has its own quickstart guide and new-comer’s tutorial: The Haskell Tool Stack and Index - The Haskell Tool Stack. GHCup does not need to duplicate that.
I would be interested to know what are the issues in practice with using HLS with Stack. As I say, I use HLS with Stack to develop Stack, and it seems to work fine, mostly. However, I don’t use Cabal (the tool), so I don’t have a benchmark.
The confusing bit for me is that the page doesn’t make it clear that there’s a decision point there. The implication is that both Stack and Cabal are required. And the descriptions don’t clarify much: “tool for managing Haskell software” vs “program for developing Haskell projects”.
(And FWIW, as a newcomer to Haskell I was playing with individual .hs
files with the help of HLS long before I started a real “project”. It’s a somewhat common pattern, I think.)
I don’t think these cases will often apply to Haskell beginners, though. As a beginner, I don’t want to pore over long comparisons of build tools that get into technical details far beyond my level – I just want to know how to get my toy program up and running.
I’m not suggesting that we as a community come out and say: “You must use Stack” or “You must use Cabal”. Rather, that we as a community should pick a path of least resistance for newcomers and document it well.
My naive summary is: HLS can’t seem to detect changes across different components in Stack projects. This can manifest in a number of vague, strange ways: obtuse HLS errors at the top of source files, files that seem to be “behind” changes in the rest of the project, or HLS simply being DOA in those files, for example. The workarounds are inconsistent and finicky, and not well-documented for new users.
EDIT: By the way, just to reiterate: I’m not trying to play favorites with Cabal here, or diss Stack. I personally strongly prefer the UX of Stack. It fits my needs perfectly, except for the HLS issues. But I do think those issues are enough to warrant questioning the idea recommending it to new users.
Frankly, IMO, Stack is dying. Usage has been dropping dramatically since Cabal added “Nix-style builds” in 2019 (unfortunately it’s been two years since the last Haskell Survey but anecdotally it seems the trend has continued). The original developers of Stack have since disappeared and the project has largely lost its momentum, and I just don’t think the community has the bandwidth to support both tools well (although @mpilgrem has been doing a lot of thankless work to keep the lights on!).
Hate to ask the question, but I wonder at what point Stack should stop being suggested by default to new users, e.g. on the downloads page…
I think this has to happen eventually, since the current situation is confusing for beginners and Stack now has few benefits and a lot of drawbacks. But it’ll take a few years, since, as @hasufell says, Cabal is yet to fully eclipse Stack in functionality. Plus, there’s a lot of politics and historical baggage surrounding all this and no one wants to reopen those wounds.
Usage has been dropping dramatically since Cabal added “Nix-style builds” in 2019
I guess you say this based on the surveys ? Please break it down for us, what data makes you think this ?
The original developers of Stack have since disappeared and the project has largely lost its momentum
Or: stack has been successfully handed off to a new more active lead maintainer, it has gained an active chat room like cabal’s, and Releases · commercialhaskell/stack · GitHub is looking pretty busy ? (Cf cabal-install releases)
I guess you say this based on the surveys ? Please break it down for us, what data makes you think this ?
To be honest, anecdotes (colleagues across multiple companies, discussions on here and at Zurihac etc…). But looking at the surveys now: we have “Stack is used by more than twice as many people as Cabal” in 2017, Cabal overtaking it narrowly in 2021, then building a 36% lead by 2022.
Okay, fair enough, I had seriously underestimated how actively developed Stack is, so kudos to @mpilgrem for that! Still, I’m not sure it changes my overall impression that Stack will become redundant eventually, and that the most important thing is to continue with the relatively small steps required to achieve parity in Cabal.
Just a quick thing to add here as well:
Lots of university courses use stack
for their course projects. I know of at least 3 very large courses (totaling over 1k students per year) that require stack
. Those sorts of users are often under-represented, since only a handful of them go on to become members of the Haskell open source community.
I don’t understand where this impression comes from. I think stack is more active now than before? Maybe it doesn’t have those big fix-all PRs from Snoyman and co or fancy blog posts with grandiose visions. But development is pretty steady.
For getting big things done, it relies on contributors more than before. E.g. Component-based builds · Issue #6356 · commercialhaskell/stack · GitHub
Although I’ve only really contributed significantly once, the process was shockingly fast. Something I can’t say about cabal, where I have a hard time getting a proper decision out of the dev team.
I had to chuckle, because those “small” steps involve things like fixing --help
, which is a humongous task, because there’s some shared logic between cabal-install and Cabal the library.
So it’s definitely not just feature parity.
For me, one of the main takeaways here is the centrality of HLS. @ktf (sweet profile pic btw) says, “[A]s a newcomer to Haskell I was playing with individual .hs
files with the help of HLS long before I started a real ‘project’”. That’s a crucial insight for Haskell tool developers. Haskell grew up in the days of running build tools from the command line, but those are specialized tools these days.
Thanks!
To expand a bit, if it’s helpful, my own progression looked something like: 0) Install everything with GHCup, 1) Mess around in GHCi a little bit, 2) Start working through beginner tutorials/books/small problems, all of which used small, single-source-file programs (HLS was still a huge help in this step!), and finally 3) Start a “real” project using Stack (though still small toy projects, initially).
So I didn’t actually touch Stack until I had built several small programs and worked through most of Get Programming in Haskell. (Which, incidentally, I loved.)
Getting back to documenting the Stack+HLS issues and their various workarounds… it’s a small thing, but to start with I’ve added a section to my big ol’ Notes of a Haskell Beginner doc. Far cry from official docs – these notes are mostly for my own consumption – but I do share them out if I think there’s stuff in there that’ll be helpful to other beginners.
That said, I still don’t have a 100%-works-all-the-time solution, or even a definitive set of specific symptoms of the problem
Great notes, thank you! (I have read only the HLS part).
One I think you haven’t mentioned: when doing Restart Haskell LSP server, do it while viewing a source file in the component you want to work with. That’ll make HLS prioritise/work best with that component.
More generally yes I know how chaotic it can feel when you see weird new error-of-the-day and none of the usual workarounds seem to help. To reliably fix HLS issues I think you really have to carefully study the Tasks > Haskell log and diagnose the underlying problem (or get the HLS room to do that for you).
Sorry to quote myself, but as another anecdotal data point, I just came across this recent post on Reddit: “Stack and Cabal, do they do same thing or different ?” At least I’m not the only one
Good point! I feel like that’s naturally how this dance tends to play out – the file you’re trying to work on is “broken”, so you restart while you’re in that file – but good to be explicit about that.
Definitely. I fully accept that no LSP experience is going to be perfect, and I don’t mind getting my hands dirty. In fact, I’m proud to say that I’ve had a couple of my own HLS bugfixes merged! (Albeit small ones.)
To me though, the issues with Stack and HLS are persistent and disruptive enough to warrant more visibility than they’ve got.