"Is cabal-install stable enough yet that GHC should be inflicting it on newbies?"

Continuing the discussion from GHC and Cabal: the big picture - #25 by AntC2

As someone who began with my Haskell journey around 2015, I find this pretty baffling. Almost anything “real” I wanted to do required libraries from Hackage:

  • networking: network, scotty, wreq.
  • GUI: gi-gtk, wx
  • TUI: brick, vty
  • images: JuicyPixels, opencv, diagrams
  • music: tidal, euterpea
  • games: gloss, SDL2, GLFW-b, OpenGL
  • window managing: xmonad
  • text editing: yi

My Haskell experience would be pretty empty without Hackage.

16 Likes

Okaaaay. (This must be some sense of “newbie” I wasn’t previously aware of :wink: )

I was hoping we’d get some feedback from those teaching on (say) ‘Intro to Functional Programming’ courses [**]. The student loads GHC; writes programs as exercises over a semester; thereafter goes away wondering why FP is so darn hard; programs in Java for the rest of their career.

  • text editing: yi

Emm you need to run cabal-install just to use an editor? I can’t just use my favourite editor for Haskell, to reduce the learning curve? Oh, no: yi “akin to unwrapping a box of lego …”. You expect a newbie would want to tinker inside an editor?/build their own? Now I’m baffled too.

[**] IIRC as of ~ten years ago, there was a lecturer used Hugs for teaching purposes, because getting GHC to run on variadic student kit was just too hard.

1 Like

I can give some of my teaching experience: Whenever I want to provide a frictionless experience for students then I prepare a template repository for them by hand which contains a minimal cabal project. We also use GitHub Classroom which automatically generates a fresh repository with starter code from the template repository for them. Even cabal init is usually too much friction, since it asks too many questions that they cannot answer with confidence. In my opinion, working with plain GHC should be considered advanced knowledge, since even I am not very sure how GHC’s builtin “make” build system exactly works and how it resolves dependencies.

12 Likes

I agree: networking, HTML templating, XML parsing (these ones more to handle HTML code snippets rather than doing SOAP) and JSON parsing libraries are what’s “in” right now to setup a minimal web server. So you see those facilities in standard libs because webdev is what’s “in” right now.

This doesn’t have to do 100% with cabal-install: after years of Java before the intro to functional programming, Haskell is very alien. Or even, after years of doing webdev (JavaScript and React) while going through university, even Java is painful and something they must slog through.

I agree, I have a minimal cabal project myself. Not because I lack confidence, however.

You are right, there is always room for improvement, as I have shown that you can cut down the “simple” cabal init into an even simpler cabal init.

I don’t mean to handwave criticisms (“everything sucks so this is fine”) or be mean to the efforts of very talented people kindly donating their time to make our time in hell more pleasant. I like to learn from the good parts of other systems.

I’m pointing out that as programmers, no matter your language, we’re pretty much stuck as friends in hell together. Not only with package managers: product distribution, cross compiling, The One True Way Of Window Managing And Graphics, et al.

Inflict it on newbies with their own personal computer? Yes.

Inflict it on universities that don’t want to spare 1 TB on all the students combined naively downloading packages into their user folder? No. Install the packages used for teaching (if any) on GHC and expose them.

On university newbies, not necessarily. You can do Advent of Code with GHC as it is. You got filesystem handling, containers (with Data.Map, the most sought out data structure thanks to JavaScript and Java), text and parsec.

On advanced university students you might want attoparsec, megaparsec, lens, optics, SDL2, gloss, warp, pandoc, criterion. Maybe. Depends on what you want to teach. About cool stuff built? Or about tools to do profiling and analyzing runtime laziness? Or about functional dependencies and type families extensions?

On students learning enterprise? The universities won’t put GHC or Cabal. The JDK has a lot of tools to zip files, move them, open servers, do requests, serialize things, deserialize things, even Swing for quick user interfaces. If the university provides Glassfish or Wildfly then you have access to the Jakarta EE suite.
And Go and Python don’t stand short, that’s why the joke of “how to do X in Python” is “import X”. The next thing they do is pip install numpy and whatever the course demands for machine learning.

This is not to be mean on GHC, this is to show that newcomers might expect a lot of “batteries-included” coming from standard libraries with a lot of tools.

3 Likes

When I first started learning haskell, pure ghc would do if I wanted modules from base. Anything outside of base, I immediately went to stack (as the book I learned taught me) and created a project. Best to do that than to figure how to deal with how ghc manages packages, what does --make do? do I have to pass libraries as arguments like with bare gcc and make? Better make a cabal/stack project, add a line in my build-depends, and everything (including hls) works as expected!

So the only things had to know were:

  • cabal/stack build
  • cabal/stack run
  • what is stack.yaml
  • and how to add dependencies to *.cabal/package.yaml
  • ghcup tui (best build tool installer i know of!)

Edit: whoops, the reply was meant to be to the thread, not this comment specifically, sorry!

2 Likes

I think cabal v1 was fine for newbies. You install a library and have it available in ghc/ghci.

Not so anymore.

Also see: [RFC] Revive cabal sandboxes (UX) · Issue #10098 · haskell/cabal · GitHub

2 Likes

Installing package A and subsequently having it available in ghc/ghci is great behaviour. Users still want it and are surprised about how difficult it is to get it. However, installing package A and subsequently losing access to unrelated (from the point of the newbie) package B is really bad behaviour (dubbed “cabal hell”). It would be great if we can find a way of resolving this tension.

It is called sandboxes :grin:

1 Like

If you enable the --write-ghc-environment-files=always option then your cabal packages act as sandboxes. That way you get the benefits of being able to configure dependencies in a text file, avoiding implicit state.

Hopefully we will also get better support for programmatically adding dependencies, so in the future you should be able to get a workflow that is much like the old sandboxes without any of the disadvantages.

are you using web-based editors yet or will students clone these repositories to their machines? Would be quite interesting to know whether one can setup a complete sandbox hosted on some university machines that provide a web-based codium and a complete environment, perhaps provisioned by nix in the background (I think the replit guys were doing something in that direction?. I don’t know whether there’s a completely free and open source, self-hostable solution for that, though. Perhaps it could also just have a “programmable run button” like e.g. lapce has. (the idea is that you provide some configuration of what a run button would do, e.g. invoke cabal run some:exe:bla

In my original Cabal woe email I describe my (faulty) model for how I should be able to add libraries to my GHC instance.

In Section 3.1 of GHC and Cabal I explain my new understanding of why my model is faulty.

Nevertheless as Tom says

Installing package A and subsequently having it available in ghc/ghci is great behaviour. Users still want it and are surprised about how difficult it is to get it.

So: would it be possible to get the following behaviour?

  • I write one file, containing a list of packages A, B, C
  • I invoke cabal to ask it to:
    • find a consistent build plan that has a mutually-consistent set of A,B,C versions
    • …compile them and install them
    • … and arrange that all of A,B,C are available by default in any subsequent invocation of that GHC, with no cabal file – just an invocation of GHC

When I want to add a new package D to the set, I’d have to re-run that process, which might involve choosing and compiling new versions of A,B,C (in order to be consistent with D). And that process might fail with “no consistent set exists”.

That can’t be hard, can it? It would mean I could “extend GHC” so that it simply knows about A,B,C,D. Of course, if you do use a cabal file, cabal invokes GHC in a way that makes it forget all prior knowledge, so that route would be entirely unaffected.

Questions:

  • How hard would that be?
  • Would it be desirable, for anyone other than me?
1 Like

You can get that behavior locally to a directory by using that --write-ghc-environment-files=always option I just mentioned. For example you can create a minimal cabal file like this:

cabal-version:   3.0
name:            sandbox
version:         0

library
    build-depends:
        base, megaparsec

And then run cabal build --write-ghc-environment-files=always. Any subsequent uses of ghc or ghci in that directory or subdirectories can now use megaparsec.

Perhaps cabal could make this workflow a bit easier with dedicated commands and cabal could also make it possible to use this approach for the global default environment. And with this minimal package format it should also be easy to create a program that adds or removes dependencies from the command line.

4 Likes

Nixpkgs’ haskell distribution does install packages alongside the ghc, i e, there’s a function ghcWithPackages that takes a function that selects packages from the haskell package set and that ghc will subsequently “know” those and only those packages.

It falls short for other reasons (uses nix) but it might be close to what you’re imagining.

I am following this discussion from these perspectives: (a) seeking intelligence on ‘what some users want’ and (b) asking myself if Stack delivers that. My impression is that Stack (stack ghci or, equivalently, stack repl) does what is being sought from Cabal (the tool): it loads up GHCi with all the library and executable components of all the packages in a Haskell project: repl command - The Haskell Tool Stack

EDIT: To elaborate, given a snapshot (and LTS 22.29 has a curated set of 3,375 packages), package.yaml listing package names under the dependencies: key is the ‘one file’ that Simon describes. That is:

stack new my-GHCi-playground
cd my-GHCi-playground
stack exec -- code . # Edit the package.yaml file to list A, B, C
stack ghci # Use GHCi with the packages you have listed
stack exec -- code . # Edit the package.yaml file to add D
stack ghci # Use GHCi with all the packages you have listed
1 Like

The current subject title of this discussion is in quotes, but I think it does not acturately characterise the current situation. The GHC project does not inflict/impose Cabal (the tool) (provided by the cabal-install package) on any user. A related question might be: “What are the relative merits and drawbacks of Cabal (the tool) and Stack for people who are new users of Haskell?”

EDIT: To give one example, @DavidB has decribed above what is effectively a ‘template’ approach to project set up in an educational context. stack new has the concept of a project template.

2 Likes

Thanks for pointing that out. As the (kinda) source of the (not actuallyrather taken out of context) quote:

  • I was only mildly questioning whether cabal-install is stable (arising from what seemed to be a surprising/controversial change in behaviour in an alleged ‘bug fix’);
  • I was much more concerned whether the whole discipline of package managing/version controlling/various hells would be a straw too many on the backs of newbies trying out a whole new programming paradigm.
  • IOW can/should we encourage a newbie to defer the cabal bit until they’re more enthusiastic about Haskell?

That’s not my read of the GHC front page. Go have a look for yourself — take with you the mindset of a newbie floundering with all this strange stuff, and anxious for comforting advice. (OK not “impose”, but you’d have to be more advanced than a newbie to see other options.)

Why do I even want a ‘project’? It’s a programming language. I want a program — to (to take a recent example for me) analyse how lucky are Euler ‘lucky primes’. Or perhaps Haskell is the wrong tool for that; I should use Python?

I understand your point about ‘I want a program’ but the terms that Stack uses need also to accomodate uses more complex than the most simple. So, a project has one or more project packages, each package can have zero or more executables (‘programs’). However:

  • somebody who types just stack new my-program gets a template for a single-program single-package project, where the executable, the package and the project all share the same name; and
  • the terms that Stack uses are explained in its Glossary: Glossary - The Haskell Tool Stack

EDIT: I am looking at Glasgow Haskell Compiler — The Glasgow Haskell Compiler but I can’t see any reference to Cabal (the tool). Can you elaborate on what you are referring to? If I were to add a sentence to that page it would be “GHC is a complex program with many ways to configure and use it. Many users of GHC do not use it directly but use it via other tools, including Cabal and Stack.”

1 Like

What you’re describing is essentially called a “world file” in package manager speak. A world file works this way:

  • installing a package explicitly (say, cabal install wombat) will record this package in said world file
  • all subsequent installations (or updates) will assume that the existing packages from the world file are to be installed/kept

This does not exist (anymore) in cabal, from what I understand (correct me if I’m wrong @andreabedini).

But you can get somewhat close to it:

$ cabal install --lib --package-env=. bifunctors
$ ls -lah
.rw-r--r-- wombat wombat 213 B  Fri Jul 19 21:54:14 2024  .ghc.environment.x86_64-linux-9.4.8
$ cat .ghc.environment.x86_64-linux-9.4.8
clear-package-db
global-package-db
package-db /home/wombat/.cabal/store/ghc-9.4.8/package.db
package-id base-4.17.2.1
package-id bifunctors-5.6.2-a7a06bbdbd7c6b866678e439ae28b310f527629610ff6010cdba7faa553d08e3
$ ghc -e 'print $ Data.Bifunctor.Joker.Joker @Maybe @Int @Int (Just 1)'
Joker {runJoker = Just 1}

Now, if you want a new package, you gotta remove the environment file and issue the extended install command:

$ rm .ghc.environment.x86_64-linux-9.4.8
$ cabal install --lib --package-env=. bifunctors hpath
$ cat .ghc.environment.x86_64-linux-9.4.8
clear-package-db
global-package-db
package-db /home/wombat/.cabal/store/ghc-9.4.8/package.db
package-id base-4.17.2.1
package-id bifunctors-5.6.2-a7a06bbdbd7c6b866678e439ae28b310f527629610ff6010cdba7faa553d08e3
package-id hpath-0.12.1-c67a3b83b660a2a0789996f5a450a6d99b392a6fdf6d10c50f0dcf2acf0efedf
$ ghc -e 'print $ Data.Bifunctor.Joker.Joker @Maybe @Int @Int (Just 1)'
Joker {runJoker = Just 1}

Again, the workflow described here would cover it better: [RFC] Revive cabal sandboxes (UX) · Issue #10098 · haskell/cabal · GitHub

1 Like

I am not using web-based editors yet. Getting a running environment is only half of the problem that has to be solved. I also need:

  • A way to automatically grade/give feedback to students. In practice this means running a CI action which has some blackbox tests that the students can’t (easily) inspect :slight_smile:
  • A way for students to hand in finished exercises.
  • A way for me to give feedback / grades for the final handin.

I’m not super happy about the non-free solution, but GitHub classroom is the easiest way to achieve this currently without wasting too much time on a custom-made solution. I create a template-repository for the starter code, GitHub actions for instant feedback, and the manual feedback is done using the normal PR review workflow. (Also, for some languages it is currently too difficult to setup a web-based editor. We are teaching the theorem prover course using Coq next semester, and I haven’t seen a satisfactory web-based solution for Coq yet).

The one tool that has made using Haskell in the classroom so much easier is GhcUp, we have so many fresh undergraduates using Windows that I couldn’t help otherwise :sweat_smile:

5 Likes

Just to provide an other data point:

At utrecht we are using Domjudge for having students hand in their solutions, and blackbox test/automatically grade it. That works pretty well. There is a sort of comments system that one could use to give feedback (but it would not be as easy/fine grained as e.g. commenting on some diff/replying to a certain line in some github PR).

Students are just installing ghc/cabal themselves (in the initial half they just need GHC, for their final project they also need cabal).

2 Likes