Convenience in the Haskell ecosystem

At work we have our own build system, we don’t use cabal. But one of the things it does is automatically include a small hardcoded set, such as text, mtl, vector and some others. It’s hardcoded for everyone and not configurable. I’ve never regretted that, and in fact I tend to forget those are not technically built in. As a contrast with cabal, the build file for an executable starts one line: haskell.executable { main = ./Thing.hs; private = [./Mod.hs Mod2.hs]; }

Part of the reason is that there is an ambient set of globally pinned versions, while cabal must live in the more complicated multi-version world. But, one line! Cabal buries me in bureaucracy about licenses and versions and descriptions and haskell language version and yes I want base and blah blah blah.

Back in cabal v1 days it was actually 0 lines, install what you want and ghc --make. Yes I know it led to its own problems and I’m not sure but cabal v2 may finally have a way to emulate the old way, but I don’t mind delaying the bureaucracy until I actually need it… and it turns out usually I don’t, since most stuff never goes to hackage.

While I’m complaining about cabal, does it still not have a way to generate the deps list from the imports? Or maybe someone wrote one and it could get integrated? Especially because in haskell module names can have nothing to do with the package name, that seems ripe to automate. I have imports automated for decades now, if I had been using cabal during that time I would probably have come up with another program to generate the import → package mapping.

1 Like

Not as far as I know. That feature sounds like a good one, and a natural extension of HLS’s feature to automatically import modules that provide the identifiers that you use.

1 Like

Are folks aware of static-ls? I’ve never used it, but it sounds like it fits the bill.

The goal of static-ls is to provide a high-speed, low-memory solution for large projects for which haskell-language-server tends to take up too much memory on recompilation.

5 Likes

This is the first I’ve heard of it, and it looks great! I’d be very happy with this as a fallback when HLS doesn’t work.

The main reason I am not using HLS is I don’t know how long it will leave. I have been doing Haskell for 20 years and I have seen countless cool projects going abandonware : ghc-mod, ghc-mod-ide, intero. In fact, the only stable tools are canal and ghc/ghci (sorry for the stack team).
Whatever people are telling me, I have no guarantee that ghcup and HLS will be still there in 5 years time (it takes 9 months to make a baby and then people realize that it is there main priority).

The only long term solution seems to merge HLS feature into ghci (with maybe a system of external plugins for exotic features). Of course if we think LSP is a long term solution itself.

2 Likes

So… I know this is all sorts of horrible, and I’m not suggesting the implementation resemble it at all, but for scaffolding a few general purpose project types with sensible defaults, could we take inspiration from:

1 Like
  1. fairly standard
  2. I’m afraid I don’t sympathize with that… unless you want our tooling to have fuzzy AI logic and guess what you might want
  3. Right… this is fixed in the VSCode haskell extension. It figures that out automatically. You can re-implement that logic for Emacs. Or use VScode haskell.
  4. Not really necessary usually
  5. That’s an issue with your editor, imo
  6. try: ghcup run --cabal latest --ghc recommended --hls latest --install -- emacs . (there’s a policy in ghcup and HLS projects that the recommended GHC always is supported by the latest HLS)
  7. your fault :stuck_out_tongue:
  8. HLS shouldn’t have to be restarted for that, imo… if it still can’t do this, there’s probably already a bug report on HLS issue tracker… maybe @fendor remembers
  9. yes, why isn’t it? Did you debug it on the cli? Troubleshooting — haskell-language-server 2.2.0.0 documentation

Overall:

  • yes, there are still rough edges and integration issues with some tools
  • some of those integration issues are the responsibility of the editor
  • ghcup can provide a temporary “virtual env”: see ghcup run --help (this logic is heavily abused by VSCode haskell extension)
3 Likes

Exactly my point! The whole reason I made this thread is to bring attention to the fact that rough edges exist, and to brainstorm some ideas about how to smooth them out a bit (so to speak).

True, but the editor is part of the tooling. (An extremely important part!)

I’m not too familiar with this tool; how is it different to, say, Stack templates?

2 Likes

Yes and HLS/GHCup devs are only involved in the VSCode Haskell extension, because that seems to yield the biggest return. If you want a similarly smooth experience for Emacs/Vim etc., you’ll have to start a project and attract contributors.

Fair enough. There’s still plenty else that can be improved, though.

1 Like

Yes, that’s not really the question.

The main question is where. Once we’ve figured out what kind of overall user experience we want, we have to figure out which abstraction is the right layer for that and what APIs the various individual tools need to provide in order to allow for that.

This is where stack took the shortcut (imo) and tried to be the layer for everything: tool installation, fixed package sets, building haskell code, nix integration, docker integration, …

It is not an easy problem.

3 Likes

I’m not too familiar with this tool; how is it different to, say, Stack templates?

One of the main differences, I suppose, is that Stack templates create … Stack projects :smiley: whereas I think these days it would be extremely convenient to have a templating setup that would create projects using different build systems/installers; i.e. ghcup, cabal, stack, various nix-y options, …

I definitely agree with @puppo that if we have something as prolific as create-react-app that would allow the community to define and maintain arbitrary Haskell-based projects to start from, that could be extremely powerful and convenient.

Honestly, in my view it’s probably an interesting and valuable-enough project that it’s worth a proposal to the Haskell foundation.

2 Likes

Agreed. I think it’s the best and easiest idea we’ve converged on in this conversation.

(In fact, I already started writing one earlier today, though I’ve realised I’m unsure what design would be best.)

3 Likes

The format used for Stack templates is based on the syntax of the Mustache tool and is, in fact, Stack-agnositic.

At the moment stack new my-project my-template, effectively, applies the template and then runs stack init. If stack new had a flag --no-init, which would be very simple to add, it could be used to create entirely Stack-free projects from templates.

4 Likes

I’m aware. It’s even been split out as project-template, which is very helpful!

2 Likes

In my early involvement with Haskell, somebody explained to me that the Haskell Tool Stack (Stack) did not follow the ‘Unix philosophy’, which I understood then to mean ‘a tool should do only one thing, and do it well’. Stack is indeed like a Swiss Army knife. The challenge is to somehow make sure that introductory users can find the main blade without needing to know (or be confused by) the fact that somewhere, tucked away in the handle, there is also a tool that will remove stones from a horse’s shoe.

8 Likes

Exactly.

But that doesn’t mean that you can’t have high-level tools that are unix philosophy. Those tools are glue abstractions over existing tools: I consider VSCode haskell extension to be fairly unix philosophy adhering. It isn’t a lot of code and its objective is to make things “just work”. It uses HLS and GHCup and some minor custom logic to achieve that.

This is on editor level… the editor is the closest we have to “end user experience” and we can make some rough assumptions about what end user experience is expected (e.g. vim vs emacs vs VSCode).

The other angle is: sane defaults.

Those are the difficult decisions: which abstraction layer should provide what… and what are sane defaults.

We have to decouple the tools from the user interface… this allows us to build different user interfaces based on the same set of core tools. And this is only possible with the unix philosophy. Otherwise we end up re-implementing and rewriting, although we just wanted a slightly different UX.

2 Likes

summoner exists but i believe has gone unmaintained. i understand people thought it was pretty handy, and it could be a good base to start from, or at least inspiration.

3 Likes

We had haskeleton too which I understand has been merged into stack and I’m pretty sure there have been a few other ones. All of them got unmaintained or forgotten for some reasons. It might be intersting to know those reasons before creating a new one. My guesses are

  • discoverability: you can’t use a tool if you are kot aware of its existence (that is the limit of the unix phylosophy)
  • difficulty to find the correct template
  • the correct template rarely exists (everybody has different needs)
  • it’s not worth the effort. It takes longer to find the template vs rolling it yourself.

An easy alternative would be to create a cabal file with the common packages commented, so the user just has to uncomment the desired packages.

Also to guaranatee that the cabal file matches version of ghc and HLS maybe that should be a job for ghcup (rather than cabal). Ghcup generates you a cabal file for the version you selected.

2 Likes

GHCup is an installer, not a cabal file templating mechanism.

This is exactly why we need unix philosophy: tool boundaries shouldn’t be violated, just because an existing tool is popular.

A unix compatible solution to this is already proposed:

4 Likes