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
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?
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.
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
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.
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.”
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
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
- 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
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).
Ok … (This was covered in the thread we split from.) The only appearance of “install” on that page:
- GHC is a breeze to install using [
ghcup
] or [Stack]
either of which leads to cabal-install
. (I agree it needs quite a bit of digging to find that out.)
If you bravely (for a newbie) take one of the [download] links at the top of that page:
… For most users, we recommend installing a [proper Haskell distribution] instead of GHC alone. …
And that page is much more explicit about cabal-install
.
You’d have to be pretty pigheaded (like me) to scroll down to the ‘Distribution packages’ and download a .tar
. (But that was the only way to go about it when I started with GHC; and indeed it’s the most common way to get going with most software I tinker with; and I want to run my virus-checker over anything before it touches my machine; and I don’t trust all those commands I see on the other approaches, especially when I see Bypass ... SecurityProtocol
.)
For you there is this link to instructions for manual installation: I don’t like curl | sh. It’s in a small font below the automatic installation command.
Personally, I don’t think those links lead to anything that is unduly Cabal (the tool)-centric. I consider the GHCup project and Haskell.org’s downloads page put Cabal (the tool) and Stack on broadly equal footing.
However, I do think that the close association of Cabal (the tool) with Cabal (the package description specification) and Cabal (the library) is a double-edged sword, in that somebody new to Haskell landing at the Cabal User Guide encounters a large document which, although structured and indexed, covers a wide territory.
Stack’s own online documentation struggles with what I call the Swiss Army knife problem - “How do you tuck away all the other tools, when a user starting out just wants the main knife?” - but it has the advantage that it is just documenting one program.
Thank you for that feedback. So my line of thought is wrt the stage of “just need GHC”.
So … ? All the Google hits that say Stack is just a different front-end to cabal-install
are wrong?
You’re expecting a newbie to be able to make a choice between different tools? I was expecting the employer or the instructor would make that choice for them. And I’m asking why that choice would necessitate 'project’s when I think all I want is programs. I’m entirely happy with multi-module programs: put all the .hs
sources in the same directory; import
them to Main
, same as import
from Base Libs (which are in a different directory, but it just works, I don’t need to worry my pretty head).
You’re just not persuading me that – at the stage of “just need GHC” – any tool, or 'project’s rather than programs will help my learning experience.
Speaking for myself (not trying to imagine how it is for a newbie): Cabal or Stack seem to be complex programs with many ways to configure and use them. I just unzipped GHC out of the box. I’m aware GHC has many options; I hardly never set any of those; I’m not seeing why I’d want to layer another option-riddled tool over the top. None of my user experience with GHC(i) has been as pleasant as with (Win)Hugs.
If somebody says Stack and Cabal (the tool) are ‘just’ different ‘front ends’, then ‘just’ and ‘front ends’ are doing a lot of heavy lifting. To explain:
- both Stack and Cabal (the tool) are built on top of Cabal (the library) but even then their approaches to Cabal (the library) are quite different. Stack follows the original Cabal specification and accesses Cabal (the library) via a ‘setup’ executable. By default (it can be overridden by using a ‘Custom’ build type), for each specified version of GHC, Stack uses the version of Cabal (the library) that ships with GHC as a boot package. Cabal (the tool), as I understand it, uses only the version of Cabal (the library) that is specified as a dependency when the tool is built and is not making use of it only via the ‘setup’ interface. That is why, when a version of GHC is released, it specifies the versions of Cabal (the tool) that it will work with. Stack does not need to be updated for the same reason (but may need to be updated for other reasons: GHC’s undocumented
hi
file format is not guaranteed to be stable and Stack sometimes parseshi
files). - Stack is also built on top of other technologies that Cabal (the tool), as I understand it, does not use. Examples are Casa (Content-Addressable Storage Archive) and Hpack (which is optional, recognisting that it has both fans and detractors). Cabal (the tool) can be used with Hpack, but only as stand alone tools.
- Stack does things that Cabal (the tool) cannot do in isolation (including for convenience) and vice versa. For example,
stack dot
is a convenient way to understand dependency relationships; Cabal (the tool) does not have an equivalent. Cabal (the tool) tries to find package versions that work well together by assuming their dependency bounds are reliable; Stack only uses ‘curated sets of packages’ to address the same problem. ‘Only’ is seen by some as a Stack limitation, but that focus of approach also brings some benefits. - Finally, I would not use ‘just’ to characterise the importance of the total user experience, including in-app and online documentation. Historically, the two projects placed different emphasis on that and, inevitably, that still has some ramifications today.
Broadly speaking, we can say cabal-install and stack are frontends to Cabal . Both tools make it possible to build Haskell projects whose sets of dependencies might conflict with each other within the confines of a single system.
I appreciate that answer is 2017, and things might have changed since. But there’s plenty of confusing-them q’s on SO and reddit; preferences seem to have changed over the years; one tool has caught up/got ahead of another; then the position reversed. (Or perhaps the answers mean that one tool is a better fit to a particular way of working – that would be your “placed different emphasis”.)
These are distinctions that are going to be way beyond a newbie’s grokking. So firstly, I think it’s incumbent on instructors to make the choice and give detailed instructions to learners/set up a learning sandbox, etc, etc. Secondly, speaking for myself, I found your long answer too much in the weeds.
So I see no strong reason to use either tool. They both seem to add unnecessary complexity. All I want is programs. GHC out-of-the-box delivers that.
Addit: Also I had this in mind, from the thread we split from (thank you @atravers )
Stack … just like Cabal-the-tool, it is implemented using Cabal-the-library. Therefore, a first answer to the questions at hand is that stack is Cabal: …
Again that’s old: 2015. If what it says no longer holds, perhaps we should enter a caveat on the original thread?
I could believe one tool is more friendly for newbies. I’m also nervous that having started with one tool, it’s awkward to switch to the other. This is a bunch of considerations we ‘just’ shouldn’t inflict on a newbie to puzzle out.
[end of Addit]