I have recently started using stack for Haskell, when specifying external dependencies for your project. Sometimes you place it in the .cabal file while other times you place it in the .yaml file.
Am I right in thinking that when you put it in the cabal file it only looks in the stackage repository for your packages. However when you place it in your .yaml file it also searches in the Hackage server, if it cannot find it in any of the snapshots?
All of the dependencies for your project go into the .cabal
file. You are correct, though, that sometimes you also list packages in the stack.yaml
file, which can be understandably confusing. Why is that?
Well, the .cabal
file always expresses your dependencies upon packages, but the stack.yaml
file effectively configures where those packages come from. Usually, when using stack
, packages come from Stackage based on the resolver you specify in the stack.yaml
file. However, Stackage does not include all the packages in Hackage, and it is not intended to—when you need packages that live outside of Stackage, you have to specify them in the stack.yaml
file.
Why is this? Well, the resolver automatically couples two important pieces of information together: package names and package versions. Stackage resolvers provide a (weak) guarantee that all of the packages within a single resolver will work together, so when a package comes from a resolver, there is no need to manually pick which version you want. Instead, Stackage will decide for you.
When pulling packages from Hackage, you do not have this luxury, so you need to specify packages and their versions using extra-deps
. For example, you might have something like this:
extra-deps:
- crypto-pubkey-openssh-0.2.7
- data-bword-0.1
- data-dword-0.3
This entry determines specifically which versions of which packages should be pulled from Hackage rather than Stackage.
When building an application, this might seem a little redundant—you can specify version constraints in the .cabal
file, too, so why duplicate them in the stack.yaml
file? However, when building a library, the distinction is a little more significant: the .cabal
file expresses the actual version constraints of your library (if any), but the stack.yaml
file specifies precisely which versions to actually install when developing locally.
In this sense, the stack.yaml
file serves a purpose similar to the Gemfile.lock
or npm-shrinkwrap.json
files of other package managers, though the responsibilities are not nearly as clear-cut with stack
(in part due to historical reasons around how Haskell’s package system works and some of the problems it’s had in the past).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With