I read this comment in the NeoHaskell thread, on convenience in the Haskell ecosystem:
As it happens, I got a taste of some of these issues just yesterday. I thought I’d write up my experiences here, in the hope of spurring some discussion on these points.
My motivation yesterday was wanting to do a spot of data analysis. Nothing complicated: essentially, I just needed to plot some fields from a JSON file.
I first tried to do this in Haskell. The steps involved were, as I recall:
cabal init
- Try to recall precisely which 10 packages I needed, and add them all to the Cabal file
- Start up Emacs… whoops, my set GHC version doesn’t have HLS, better change that…
- Add a
cabal.project
with a more appropriate GHC version, remembering of course to fix thebase
version - Start up Emacs again… wait, why is HLS using the wrong compiler version?
-
ghcup set ghc 9.2.7
just to be completely sure - Finally start writing code… oh wait, I forgot to add a package to do HTTP requests…
- Add
wreq
to the Cabal file, restart HLS - Start writing code for the second time… wait, why isn’t HLS reporting errors properly?
- Give up on HLS, use
cabal build
instead to find type errors - Finally make good progress, but find
Charts
a little too restrictive for my needs
At this point, I gave up on Haskell and reluctantly decided to try Python instead, where it went like this:
- Create a virtualenv
- Activate the virtualenv
pip install jupyter matplotlib
jupyter notebook
- Make good progress.
Now, I want to emphasise at this point that Haskell’s solutions are actually technically superior. Virtualenvs are a monstrous hack which should never have been necessary, and Jupyter is, let us say, not a great environment for editing. Meanwhile, Cabal and Emacs are both great pieces of software. Even comparing Charts
vs matplotlib
, it feels safe to say the former has the better design, even if matplotlib
is more featureful.
But, when it comes to convenience, Python wins hands down. HLS, for instance, is… not actually unstable, as such, but certainly requires a bit of care every now and then. (I still have no idea why it suddenly stopped working properly last night, though I’m sure I’ll figure it out eventually.) Having to remember to add the right libraries for your usecase — aeson, wreq, lens, Chart, Chart-gtk, text, …
— is a bit of a pain compared to Python’s ‘batteries-included’ standard library and ecosystem. And various things are incompatible in subtle ways which are only obvious to someone with more experience. (GHC version requires HLS version and base
version which affects other versions…)
So what’s the solution? I’m not entirely sure, but what I want is a workflow which looks something like this:
-
cabal init
creates a sane Cabal file, with a good set of default packages -
cabal add Charts Charts-gtk wreq
for the extra packages - Open up Emacs, and HLS works immediately with my compiler version
It would require a lot of coordination between community members, but I hope that something like this should one day be possible.
EDIT: On reflection, I’ve realised that most of the papercuts I mentioned are to do with HLS specifically. And, in particular, the fact that maintaining it for different GHC versions is a major pain. Perhaps we should direct more efforts towards solving this problem (though I know there’s work being done on the GHC API already).
EDIT2: Figured out the HLS error messages problem I mentioned earlier. It was because HLS was for some reason not detecting that I had a Cabal file, so it couldn’t find modules from my dependencies. Adding an hie.yaml
fixed the problem.
This, let me note, is yet another problem which requires a lot of experience to diagnose and solve. Ideally, beginners shouldn’t even need to know what an ‘HIE cradle’ is, let alone need to write one manually…