Cabal + Stack: specifying the packages version in the cabal file - haskell

Normally when adding a new dependency to a .cabal file I specify the version of the new library I'm depending on. However stack works with a curated set of libraries, and I'm wondering whether it makes sense to specify the package versions in the .cabal file. My guess would be that specifying the lts version in the stack.yaml is enough.

I'm wondering whether it makes sense to specify the package versions in the .cabal file.
That depends completely upon you. If you specify a package version
which is not in that particular stackage resolver, then Stack will
throw an error saying you to adjust the versioning.
My guess would be that specifying the lts version in the stack.yaml is enough.
For private packages, it doesn't matter and I prefer not putting any version bounds there. But if it's something I ultimately plan to publish on Hackage, I usually use a CI system like Travis and get the bounds right for it with some testing. In fact, I think the Stack guide recommends something like that.

Related

How does the workflow with Haskell Stack work?

I don't get the point about Stack.
I used to write my Haskell code in my favourite environment, ran or compiled using GHC(i), and if necessary, installed packages using Cabal. Now, that apparently is not the way to go any more, but I don't understand how to work with Stack. So far, I have only understood that I need to write stack exec ghci instead ghci to start a repl.
Apart from that, the docs always talk about 'projects' for which I have to write some yaml files. But I probably don't have any project -- I just want to launch a GHCi repl and experiment a bit with my ideas. At the moment, this fails with the unability to get the packages that I want to work with installed.
How is working with Stack meant? Is there any explanation of their use cases? Where do I find my use case in there?
Edit. My confusion comes from the fact that I want to work with some software (IHaskell) whose installation guide explains the installation via stack. Assuming I already have a GHCi installed whose package base I maintain e.g. using Cabal. How would I have to set up stack.yaml to make stack use my global GHCi for that project?
First, notice that stack will use its own package base independent from cabal. AFAIK they can't be shared... hence, if you run stack build it'll download packages (including the compiler) on its own package database.
Nevertheless stack allows to use a system compiler (but not other libraries). To do so, in the stack.yaml you must have the following two lines
resolver: lts-XX.XX -- keep reading below
system-ghc: True
The version of the stackage snapshot can be found in: https://www.stackage.org/. Each snapshot works with a different version of the compiler. Be sure to use a snapshot with the same compiler version you have in you system. If it happens your system ghc is greater than any lts, then you can set allow-newer: true in stack.yaml.
Now, if getting a different database from stack feels wrong to you, notice that you can build the project with cabal too, since stack at the end of the day spits out a cabal file. Probably, It wont work out of the box if you build with cabal. You can modify the cabal file to match exactly the version of the packages of the snapshot you are using
In summary:
You can use your system-wide ghc
you can not share libraries installed with cabal.
you can use cabal to build the project, probably modifying the ihaskell.cabal file to match versions of the stackage's snapshot.

Nested git dependencies when using Stack (Haskell)

I have two Haskell libraries lib-a and lib-b, both hosted on private git repos. lib-b depends on lib-a, both build with no problem.
Now i want to import lib-b into another project and thus add it to the stack configuration with the git directive, like this:
- git: git#github.com:dataO1/lib-b.git
commit: deadbeef102958393127912734
Stack still seems to need a specific version for lib-a:
In the dependencies for application-0.1.0.0:
lib-a needed, but the stack configuration has no specified version (no package with that name found,
perhaps there is a typo in a package's build-depends or an omission from the stack.yaml packages
list?)
needed due to application-0.1.0.0 -> lib-b-0.1.0.0
The question now is, can stack somehow figure out specific versions for nested git dependencies without explicitely specifying them? If the project grows i dont want to manually adjust this every time i update lib-a.
Sidenote: I'm using nixOS and the nix directive for all three stack projects.
Stack follows the snapshot-based model of package management, meaning that it has some "globally" specified set of packages (of fixed version) that you can use. In Stack's case this set of packages is called Stackage. The core idea is to have this clearly specified set of packages that you're working with.
So the short answer is no it cannot figure it out by itself, you have to add them by hand.
But! you need to specify only packages that are not in the snapshot. e.g. package lib-a is likely to depend on mostly packages that are commonly used in Haskell (e.g. base, aeson, ...) and those will already be in Stackage. so even if the project grows you will be adding just "a few" git refs.
So this doesn't generally tend to be a problem.

stack: why the version constraint on base?

It is my understanding that when using stack to compile a project, no version constraints for dependencies should go in the .cabal (or package.yaml) files, because the resolver picks specific versions for you. This includes the GHC version and its base library. However, when creating a new project with stack new, it automatically adds a version constraint to the dependency to base.
Excerpt of auto-generated package.yaml
dependencies:
- base >= 4.7 && < 5
Why is that?
I don't know the canonical answer. But here's one reason why it might be nice.
For what is currently the only realistic implementation of Haskell, namely, GHC, the base version and the compiler version are inextricably linked. This means that suitable base constraints also communicate which version of the compiler is intended to be used.
That latter piece is interesting information to know about a package at a glance.
Now, it's also true that stack resolvers and GHC versions are inextricably linked. So you might think that information is already available. BUT currently, Hackage (the place that most Haskell packages get hosted for use by others) displays a bunch of information taken from cabal files, but no information taken from stack files. So if you want the information about GHC version to be conveniently available from the autogenerated Hackage summary of the package, this is one way to easily and automatically do that.

Broken dependency in haskell stack?

I am relatively new to haskell, stack, ghc, etc.
Have been trying a few projects with ghcjs and haven't been able to build any of them, including reflex-dom-stack-demo. I am getting the following error:
In the dependencies for semigroupoids-5.0.0.4:
tagged-0.8.1 from stack configuration does not match >=0.8.5 && <1 (latest matching version is 0.8.5)
needed due to ghcjs-0.2.0 -> semigroupoids-5.0.0.4
Now I cannot understand whether I misconfigured something or there is truly a broken dependency. Deleted ~/.stack multiple times throughout my experiments.
I found this bug in stackage but am unsure whether this is what affects me, and whether it would be fixed once the fix moves through.
Using Ubuntu 17.10..
Any insight is welcome.
The recomended way to create a development environnement for reflex-dom is to use try-reflex.
It is tricky to build reflex-dom with stack, because some needed changes have not yet been added to the upstream libraries.
If you really want to build a reflex-dom environnement with stack, please consider these hints:
Do not use a GHC compiler with a version higher than 8.0.2
Do not use the reflex /reflex-dom versions from Hackage, they are outdated.
Use versions of reflex / reflex-dom from Github.
This repo contains a stack.yaml file, that used to work.
You may also try the stack.yaml file from the answer to this SO question.

stack.yaml file & .cabal file differences?

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).

Resources