├── 2019-08-03-q-and-as-about-nix-for-haskellers.md └── README.md /2019-08-03-q-and-as-about-nix-for-haskellers.md: -------------------------------------------------------------------------------- 1 | title = Questions and Answers about Nix for Haskellers 2 | tags = haskell, nixos 3 | summary = Overview of Nix for Haskell development 4 | draft = true 5 | 6 | ------------------------------------------------------ 7 | 8 | Last week Dmitrii Kovanikov ([@ChShersh](https://twitter.com/ChShersh)) posted 9 | a [request](https://twitter.com/ChShersh/status/1154782785967542272?s=20) on 10 | Twitter asking if anyone had the time to answer some questions about how to 11 | understand Nix as it applies to Haskell programming. 12 | 13 | Dmitrii is working on a scaffolding tool for Haskell projects called 14 | [summoner](https://github.com/kowainik/summoner). There is an 15 | [open PR](https://github.com/kowainik/summoner/pull/283) adding Nix support. 16 | However, Dmitrii doesn't have any Nix experience, so he'd like to learn more 17 | about using Nix for Haskell development before tackling the PR. 18 | 19 | I've been using Nix for about a year and half, both at work and on my own 20 | projects. I think there is a big lack of documentation surrounding Nix and 21 | Haskell, so I told him I'd be able to answer any questions he had. 22 | 23 | He wrote me back with a _great_ list of questions. I thought it would be an 24 | injustice to the Haskell community if I didn't share my answers, so I decided 25 | to turn his questions and my answers into an article. 26 | 27 | This article is mainly for Haskellers that have heard about Nix (on Twitter, 28 | Reddit, YouTube, etc), know about its advantages, but haven't actually played 29 | around with it. It is mainly a **high-level overview** of how Nix works with 30 | Haskell. It is not a hands-on tutorial or walk-through. 31 | 32 | The first section of this article is an intro to Nix, followed by answers 33 | to each of Dmitrii's questions.[^7] 34 | 35 | ## Intro 36 | 37 | You may have heard that Nix is complicated and hard to learn. In my 38 | experience, this is true. 39 | 40 | It is similar to Haskell. The learning curve is steep, but once you get the 41 | hang of it, it is very powerful and flexible. 42 | 43 | *What makes it so hard?* 44 | 45 | To start off with, Nix refers to two things: 46 | 47 | 1. A programming language for defining _derivations_ 48 | 49 | 2. A set of command line tools for actually building and installing _derivations_ 50 | 51 | What is a _derivation_? You can think of it as something similar 52 | to a "package" in a distribution like Debian or Fedora. 53 | 54 | The Nix language provides a way of defining derivations. The following code 55 | shows an example of defining a derivation for the GNU 56 | [hello](https://www.gnu.org/software/hello/hello.html) package[^1]: 57 | 58 | ```nix 59 | stdenv.mkDerivation { 60 | name = "hello-2.1.1"; 61 | builder = ./builder.sh; 62 | src = fetchurl { 63 | url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz; 64 | sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465"; 65 | }; 66 | ``` 67 | 68 | As far as the Nix language is concerned, you can think of a derivation as a 69 | dictionary of key-value pairs. Some of the keys (and corresponding values) are 70 | considered "special". For instance, in the above definition, `builder` is a 71 | special key that corresponds to a shell script. The shell script contains 72 | commands like `./configure && make && make install` that will be used to 73 | build and install the package. 74 | 75 | Nix has a few well-known CLI tools. In this article I will mostly talk about 76 | `nix-build` and `nix-shell`. `nix-build` would take the above derivation and 77 | actually build it. `nix-build` uses the "special" keys in the 78 | above derivation to run shell scripts to build and install the binaries, shared 79 | objects, header files, and other files associated with the package.[^2] 80 | 81 | For instance, if the above derivation is saved in a file called 82 | `my-first-derivation.nix`, you can build it with the following command:[^3] 83 | 84 | ``` 85 | $ nix-build ./my-first-derivation.nix 86 | ``` 87 | 88 | This produces a directory in the Nix store called something like 89 | `/nix/store/06vykrz1hmxgxir8i74fwjl6r9bb2gpg-hello-2.10`. This contains, among 90 | other things, the `hello` binary: 91 | 92 | ``` 93 | $ /nix/store/06vykrz1hmxgxir8i74fwjl6r9bb2gpg-hello-2.10/bin/hello 94 | Hello, world! 95 | ``` 96 | 97 | *That doesn't sound too bad. Where is the difficulty?* 98 | 99 | If this was all there is to Nix, it wouldn't be too difficult. However, it 100 | also wouldn't be that helpful. 101 | 102 | The other big part of Nix is a huge set of pre-defined derivations and helper 103 | functions in a repo called [nixpkgs](https://github.com/NixOS/nixpkgs). 104 | This repository contains tens of thousands of derivations, as well as hundreds 105 | of helper functions. In practice, almost no one uses the bare Nix language by 106 | itself. Almost everyone uses Nix with nixpkgs. 107 | 108 | So what makes learning Nix hard? In my opinion, it is the following three things: 109 | 110 | 1. The documentation for Nix is both terrible and great at the same time. The 111 | main documentation for the Nix language and CLI tools is in the 112 | [Nix manual](https://nixos.org/nix/manual/). The main documentation for the 113 | derivations and helper functions in nixpkgs is the 114 | [nixpkgs manual](https://nixos.org/nixpkgs/manual/). 115 | 116 | For the most part, these manuals are written as reference manuals rather 117 | than beginner-oriented HOW-TO manuals. As a beginner, it is quite difficult 118 | to figure out how to do things just from the above manuals.[^4] 119 | 120 | 2. Nix is a dynamic language. Unlike Haskell, you don't get "documentation for 121 | free" with type signatures. 122 | 123 | There are no tools similar to [Haddock](https://www.haskell.org/haddock/) 124 | or [doctest](https://github.com/sol/doctest) for Nix. 125 | 126 | 3. nixpkgs is a lot of things to a lot of people. There are a large number of 127 | people using nixpkgs for widely different things. There are people who use 128 | it purely as a repository for system packages (like zlib, glibc, GTK, etc). 129 | There are people who use it for easily generating a GHC package database 130 | containing packages like aeson, lens, etc for Haskell development. There 131 | are people who use it for doing Python development. There are people who 132 | use it for cross compiling ARM binaries on x86. And many more. 133 | 134 | All of these groups of people have their own code in nixpkgs that others 135 | often don't venture into. For example, I've been using Nix for 136 | about a year and a half, but I don't really have any idea how the 137 | Python libraries are structured, how cross compiling works, etc. 138 | 139 | If I wanted to play around with cross compiling, it would be time-consuming 140 | to come up to speed with how everything works. 141 | 142 | Learning Nix is a non-trivial endeavour. However, Nix is extremely flexible. 143 | Like Haskell, I'd say the time-investment can be worth it depending on how 144 | extensively you're planning on using it. 145 | 146 | With the above knowledge, it should be possible to dive into the questions from 147 | Dmitrii. 148 | 149 | ## Questions and Answers 150 | 151 | Below, I list Dmitrii's questions and answer them one-by-one.[^7] These answers 152 | should be understandable by people with no experience using Nix. 153 | 154 | ### 1. What is the difference between `nix-build` and `nix-shell`? 155 | 156 | `nix-build` and `nix-shell` are the two most widely used Nix tools. 157 | 158 | They both evaluate derivations in a similar way, but their final results are 159 | different. 160 | 161 | When `nix-build` is finished evaluating a derivation, it produces a directory 162 | in the Nix store containing the binaries, shared objects, header files, etc for 163 | the derivation. 164 | 165 | When `nix-shell` is finished evaluating a derivation, it launches a Bash shell. 166 | It makes all the inputs to the derivation available in the Bash shell. For 167 | instance, imagine you had a derivation that depends on `git`. If you ran 168 | `nix-shell` on that derivation, it would put you in a Bash shell with an 169 | environment where the `git` CLI tools available. From `nix-shell`, 170 | it should be possible to build the derivation manually (running commands like 171 | `./configure && make && make install`). 172 | 173 | By default, if you give no arguments to `nix-build`, it looks for a file called 174 | `default.nix` in the current working directory. It assumes this file defines a 175 | derivation. It builds this derivation. 176 | 177 | If you give no arguments to `nix-shell`, it looks for a file called `shell.nix` 178 | in the current working directory. It assumes this files defines a derivation. 179 | It takes all the inputs from this derivation and launches a Bash shell with all 180 | these inputs available. 181 | 182 | In later questions, I talk about how `nix-build` and `nix-shell` are related to 183 | doing Haskell development. 184 | 185 | ### 2. When would somebody want to use Nix instead of cabal or stack? 186 | 187 | In general, there are three ways to use Nix to build Haskell projects: using 188 | `nix-build` directly, using `cabal` + Nix, or using `stack` + Nix. 189 | 190 | But before I describe each of these methods, I need to talk about Haskell 191 | package sets in Nix. 192 | 193 | As explained in the previous section, the Nix language provides a way to define 194 | a _derivation_. A derivation describes the build steps for building a library, 195 | a binary, etc. 196 | 197 | The nixpkgs repo provides functions that make it easy to define a derivation 198 | for a Haskell package. 199 | 200 | A derivation for a Haskell package might look like the following: 201 | 202 | ```nix 203 | mkDerivation { 204 | pname = "conduit"; 205 | version = "1.3.1.1"; 206 | sha256 = "84dfafc92e9553c7bae4b4fe0cba3da29b37def606f88b989db95ee2dc933fa2"; 207 | libraryHaskellDepends = [ 208 | base bytestring directory exceptions filepath mono-traversable mtl 209 | primitive resourcet text transformers unix unliftio-core vector 210 | ]; 211 | doHaddock = false; 212 | doCheck = false; 213 | homepage = "http://github.com/snoyberg/conduit"; 214 | description = "Streaming data processing library"; 215 | license = stdenv.lib.licenses.mit; 216 | } 217 | ``` 218 | 219 | This is a derivation for building `conduit`. You can see that it just 220 | duplicates some of the info from the `.cabal` file.[^5] 221 | 222 | nixpkgs provides a set of these Haskell derivations for building all the 223 | Haskell packages from Hackage. nixpkgs provides easy ways of injecting your 224 | own packages into this package set, or changing the versions of packages in 225 | this package set (you can see above that the `conduit` version is fixed to 226 | version 1.3.1.1). nixpkgs also provides a way to define your own custom 227 | Haskell package set. 228 | 229 | The Haskell package set is used in different ways depending on whether you're 230 | using the Nix CLI tools, using `cabal` + Nix, or using `stack` + Nix. I 231 | describe each of these methods below: 232 | 233 | 1. _Use `nix-build` from the CLI to build Haskell projects._ 234 | 235 | This method doesn't directly involve `cabal` or `stack`.[^6] 236 | 237 | In this method, the developer generates a derivation corresponding to the 238 | Haskell package they are developing. They then call `nix-build` on this 239 | derivation. When `nix-build` tries to build the derivation, it gets 240 | Haskell dependencies from the nixpkgs Haskell package set. It also gets 241 | system dependencies (like `zlib` or PostgreSQL bindings) from nixpkgs. 242 | 243 | `nix-build` is not good for interative development, since it doesn't know 244 | how to only rebuild parts of your code that have changed. It does a full 245 | rebuild every time it is run. 246 | 247 | `nix-build` is mainly used in two different situations. One is by 248 | end-users who are trying to install an exectuable written in Haskell. 249 | For instance, if you want to try out the terminal emulator 250 | [Termonad](https://github.com/cdepillabout/termonad), 251 | you can just clone the repository and run `nix-build`. You don't have to 252 | worry about having `stack` or `cabal` on your system, or making sure any of 253 | the GTK libraries are installed. `nix-build` handles everything for you. 254 | 255 | The other situation is in CI. Using `nix-build` in CI gives extremely high 256 | confidence that your build is actually reproducible. In practice this ends 257 | up being much nicer than directly calling `stack` or `cabal`. 258 | 259 | 2. _Use `cabal` + Nix to build Haskell projects._ 260 | 261 | This method uses a combination of `cabal` and Nix. 262 | 263 | In this method, Nix is used to build a GHC package database of all your 264 | Haskell dependencies (as well as their required system packages). 265 | For instance, if you're developing a Haskell package that uses 266 | [`postgresql-simple`](http://hackage.haskell.org/package/postgresql-simple), 267 | Nix will compile `postgresql-simple` as well as its Haskell dependencies 268 | like `aeson`, `attoparsec`, etc. It will then produce a GHC package 269 | database with all these dependencies available. 270 | 271 | Normally, you will run `nix-shell` to get into a Bash shell with this GHC 272 | package database available. The shell will have the required system 273 | libraries available, like `libpq` and `zlib`. The shell will also provide 274 | build tools like `cabal` and `ghcid`. 275 | 276 | From here, you can run `cabal` commands like normal. `cabal` will be able 277 | to see the GHC package database provided by Nix. `cabal` won't have to compile 278 | any dependencies when you run commands like `cabal new-build all` for the 279 | first time. The only thing it will ever need to build is your own project. 280 | 281 | This method is nice for interactive, everyday development. 282 | 283 | 3. _Use `stack` + Nix to build Haskell projects._ 284 | 285 | `stack` has built-in support for working with Nix, although it works 286 | slightly different than `cabal`. 287 | 288 | When using `stack` with Nix, you need to do two things. One is to pass the 289 | `--nix` flag to `stack`. The other is to edit the `stack.yaml` file and 290 | specify a location of a Nix file containing a derivation. This derivation 291 | should contain all the system libraries that are dependencies for the 292 | Haskell libraries you are using. For instance, if you are developing a 293 | package that depends on the `postgresql-simple` package, the derivation 294 | needs to contain the `libpq` and `zlib` system libraries. 295 | 296 | When you run `stack --nix build`, `stack` internally executes `nix-shell` 297 | with the derivation you have provided. It then re-executes itself in this 298 | new environment. Now that it is running in an environment with all the 299 | required system libraries, it starts to compile all your Haskell 300 | dependencies. Finally, it compiles your actual project. 301 | 302 | Unlike with `cabal`, `stack` has no way of directly using a GHC package 303 | database provided by the user. Unfortunately, there is no way of building 304 | Haskell packages with Nix and making `stack` use them. 305 | 306 | This method is nice for people and teams already using `stack`, but have 307 | complicated system dependencies. 308 | 309 | The `stack` documentation has a 310 | [nice section](https://docs.haskellstack.org/en/stable/nix_integration/) 311 | about integration with Nix. 312 | 313 | If you're looking to use Nix for Haskell development, I recommend setting up 314 | your CI to use `nix-build`, and then using `cabal` + Nix for everyday 315 | development. If your team is already using `stack`, then using Nix to provide 316 | system dependencies can be a nice way to make your project fully reproducible 317 | (since `stack` only deals with making the Haskell-part reproducible). 318 | 319 | ### 3. How can I specify the version of Haskell packages to use? 320 | 321 | When building with `nix-build` directly, or using `cabal` + Nix, you need a way 322 | to specify to Nix the versions of the Haskell packages you depend on. For 323 | instance, if you depend on an older version of `aeson`, you need to make sure 324 | that Nix doesn't accidentally use a recent version. 325 | 326 | In general, there are two ways to fix Haskell package versions. One way is to 327 | use the Haskell package set defined in nixpkgs, and overwrite individual 328 | packages that should be different. The other way is to completely generate your 329 | own Nix Haskell package set. 330 | 331 | 1. _Overwrite individual entries in the Haskell package set in nixpkgs._ 332 | 333 | As explained above, nixpkgs has a built-in Haskell package set. In 334 | general, each package is set to the latest version on Hackage[^8]. 335 | 336 | If you need to use an older version of a package, you can easily overwrite 337 | packages in the nixpkgs Haskell package set. For instance, if you need to 338 | an older version of `aeson`, you can just specify it in your Nix files. 339 | 340 | If you're working on a small open source package with few dependencies, 341 | this is an easy method to implement. 342 | 343 | If you're working on a large proprietary application, this method can be 344 | quite a lot of tedious work. You're effectively performing the work of 345 | the `cabal` solver, only manually. 346 | 347 | 2. _Generate your own Nix Haskell package set._ 348 | 349 | If you're working on a large Haskell project with many dependencies, it is 350 | often convenient to generate a Haskell package set for use in Nix. 351 | 352 | There are two main ways people generally generate these Haskell package sets. 353 | 354 | One is by using the output of the `cabal` solver and translating the build 355 | plan to a set of Nix derivations. The other is by using a Stackage LTS 356 | package set and translating it to a set of Nix derivations. 357 | 358 | Generating your own Nix Haskell package sets can make sure that you are 359 | getting the exact same versions of your Haskell dependencies whether you're 360 | building with `nix-build`, plain `cabal`, `cabal` + Nix, plain `stack`, or 361 | `stack` + Nix. This can make Nix easy to use on teams where some people 362 | prefer `cabal` (without involving Nix at all), some people prefer `stack` 363 | with Nix integration, and some people want to run `nix-build` on CI, etc. 364 | 365 | There are tools for generating a set of Nix derivations from either the 366 | output of the `cabal` solver or a Stackage package set. The two most 367 | well-known tools are 368 | [`haskell.nix`](https://github.com/input-output-hk/haskell.nix) 369 | and [`stack2nix2`](https://github.com/input-output-hk/stack2nix). 370 | 371 | I wrote up a short 372 | [comparison](https://discourse.nixos.org/t/backport-ghc-8-6-5-to-19-03/3040/7?u=cdepillabout) 373 | of these two tools on the offical 374 | [Nix Discourse](https://discourse.nixos.org). 375 | 376 | Generating your own Nix Haskell package set is often overkill if you're 377 | only writing a small library, but it works very well if you're on a large 378 | team or working on a big project. 379 | 380 | ### 4. Minimum required configuration for Haskell with Nix 381 | 382 | _What is the minimum required configuration for a Haskell project to be built 383 | with nix?_ 384 | 385 | This is a difficult question to answer. The downside of the flexibility of Nix 386 | is that it provides many different ways to integrate with Haskell projects. 387 | 388 | The minimum required configuration changes depending on whether you want to 389 | build purely with `nix-build`, you want to provide a `cabal` + Nix development 390 | environment, you want to allow building with `stack`, etc. It also depends on 391 | whether you want to use the Haskell package set defined in nixpkgs, or you want to 392 | generate your own Haskell package set (as described in the previous question). 393 | 394 | I've setup a 395 | [repo that showcases](https://github.com/cdepillabout/nix-cabal-example-project) 396 | a minimum required configuration for building a non-trivial Haskell project 397 | with both `nix-build` and `cabal` + Nix. It uses the nixpkgs Haskell package 398 | set. The README describes how it can be used. 399 | 400 | If you want to build with both `nix-build` and `cabal` + Nix, but use a package 401 | set generated from the `cabal` solver, you can use 402 | [`haskell.nix`](https://github.com/input-output-hk/haskell.nix). 403 | 404 | If you want to build with `nix-build`, `cabal` + Nix, and `stack`, while using 405 | a package set based on a Stackage LTS release, you should also be able to use 406 | `haskell.nix`. 407 | 408 | If you want to build with `stack`, using Nix only for system dependencies, look 409 | at the Stack documentation on 410 | [Nix integration](https://docs.haskellstack.org/en/stable/nix_integration/). 411 | 412 | ### 5. Difference between `nix-build` and `nix-shell` for developing Haskell projects 413 | 414 | _What is the difference between `nix-build` and `nix-shell` with respect to 415 | developing Haskell projects?_ 416 | 417 | As described above, by default `nix-build` looks for a file called 418 | `default.nix`. This file should define a derivation. `nix-build` builds this 419 | derivation. 420 | 421 | `nix-build` is used to build a Haskell package. The resulting Haskell 422 | libraries (shared objects), Haskell executables, documentation, etc are created 423 | in a directory in the Nix store. The Haskell executables can be run directly, 424 | moved to other systems, etc. 425 | 426 | By default `nix-shell` looks for a file called `shell.nix`. This file should 427 | define a derivation. `nix-shell` pulls out all the input derivations for the 428 | given derivation. `nix-shell` launches a Bash shell in an environment with all 429 | the input derivations available. 430 | 431 | `nix-shell` is used in two ways for Haskell development. 432 | 433 | 1. With `cabal`. 434 | 435 | `nix-shell` compiles all your system dependencies, as well as all your 436 | Haskell package dependencies. It launches you into a Bash shell with 437 | access to a GHC package database containing of all these dependencies. If 438 | you run a command like `cabal new-build all`, `cabal` will be able to see 439 | the GHC package database. `cabal` will not have to compile any of these 440 | Haskell dependencies. 441 | 442 | 2. With `stack`. 443 | 444 | This method uses `nix-shell` to provide system-level dependencies, while 445 | using `stack` to compile all Haskell packages. 446 | 447 | When running `stack --nix build`, `stack` internally executes `nix-shell`, 448 | and re-executes itself inside that environment. This is described in more 449 | detail above. 450 | 451 | A third possibility would be to use `nix-shell` to provide system-level 452 | dependencies, but use `cabal` to compile all Haskell packages. This would be 453 | similar to how Stack's Nix integration works. This method is not often used. 454 | 455 | ### 6. default.nix, shell.nix, and release.nix 456 | 457 | _I've heard about some common Nix files: default.nix, shell.nix, and 458 | release.nix. What is the purpose of these files?_ 459 | 460 | As described above, by default, `nix-build` reads `default.nix`. `nix-shell` 461 | reads `shell.nix`. 462 | 463 | As for other commonly seen files, like `release.nix`, `nixpkgs.nix`, etc, 464 | none of them have any special meaning. There is no standard for what to name 465 | these other files. There are no widely-followed best practices regarding 466 | naming. 467 | 468 | That said, most repositories meant to built with Nix have at least three files. 469 | The first two files are `default.nix` and `shell.nix`. The third file often 470 | defines the nixpkgs version you want to use, as well as an overlay that defines 471 | your own packages. 472 | 473 | This isn't super important to understand right now, but you can see an example 474 | of it in action in the 475 | [example repo](https://github.com/cdepillabout/nix-cabal-example-project). 476 | I've called this third file 477 | [`nixpkgs.nix`](https://github.com/cdepillabout/nix-cabal-example-project/blob/master/nixpkgs.nix). 478 | 479 | ### 7. What is the recommended workflow when developing packages with nix? 480 | 481 | The recommended workflow depends on whether you want to use `cabal` or `stack`. 482 | 483 | 1. With `cabal`. 484 | 485 | First, you run `nix-shell` to get into a Bash shell. This Bash shell has 486 | tools like `cabal-install` and `ghcid` available. There should also be a 487 | GHC package database with all your Haskell dependencies available. From 488 | this Bash shell, you should directly be able to run commands like the 489 | following: 490 | 491 | - `cabal new-build` 492 | - `cabal new-test` 493 | - `ghcid -c 'cabal new-repl'` 494 | 495 | You can play around with the 496 | [example repo](https://github.com/cdepillabout/nix-cabal-example-project) 497 | for an idea of what this workflow feels like. 498 | 499 | 2. With `stack`. 500 | 501 | You can directly run commands like the following: 502 | 503 | - `stack --nix build` 504 | - `stack --nix test` 505 | - `ghcid -c 'stack --nix repl'` (given that you already have `ghcid` 506 | available in your environment) 507 | 508 | In the above commands, `stack` makes sure to re-exec itself in an 509 | environment with all your required system libraries. 510 | 511 | See Stack's 512 | [Nix integration](https://docs.haskellstack.org/en/stable/nix_integration/) 513 | documentation for more information. 514 | 515 | When building on CI, you should set everything up so your Haskell package is 516 | built with `nix-build` directly. 517 | 518 | ### 8. Haskell + Nix uses too much disk space? 519 | 520 | _I know that nix has its own store for storing packages. Is it possible to 521 | configure it to share the store for Haskell packages with cabal 522 | (`~/.cabal/store`) and stack (`~/.stack`)? I'm building with both build tools 523 | and caches for them eat a lot of my disk space. I don't really want to 524 | duplicate every Haskell package 3 times for nix as well._ 525 | 526 | This is a tricky question. The answer depends on the following questions: 527 | 528 | 1. Do you want to use `stack` or `cabal`? 529 | 530 | 2. If you answered `cabal`, then do you always want to get Haskell dependencies 531 | from Nix? Or do you want to build some packages fully with `cabal`, and 532 | some packages with `cabal` + Nix? 533 | 534 | If you are content with doing all development with `stack`, then you can 535 | continue to use `stack` as normal (with or without the Nix integration). 536 | All the Haskell dependencies `stack` builds will go under `~/.stack` like 537 | normal. 538 | 539 | There is no way to get `stack` to use Haskell dependencies built with Nix. 540 | 541 | If you want to use `cabal`, then you have to decide whether you want to use 542 | `cabal` + Nix for some projects and use normal `cabal` (without Nix) for some 543 | projects, or you want to use `cabal` + Nix for ALL projects. 544 | 545 | If you want to use `cabal` + Nix for ALL projects, then in theory you can keep 546 | nearly all Haskell dependencies in the Nix store. However, if you use 547 | different versions of nixpkgs to get Haskell dependencies for different 548 | projects, or if you use a tool like `haskell.nix` to generate a custom Haskell 549 | package set, then it is possible for many duplicate Haskell packages to end up 550 | in the Nix store. This can eat up disk space. 551 | 552 | If you want to use `cabal` + Nix for some projects and normal `cabal` (without 553 | Nix) for some projects, then you will end up with duplicate Haskell packages in 554 | the Nix store and `~/.cabal/store`. 555 | 556 | If you want to use a combination of Nix, `cabal`, and `stack`, then you will 557 | end up with a bunch of duplicate Haskell packages. 558 | 559 | The only solution to this problem is to use `cabal` + Nix while getting all 560 | your Haskell dependencies from the same Nix Haskell package set for all your 561 | projects. Unfortunately, this is often not a reasonable solution. 562 | 563 | ### 9. What is the best way to learn Nix for Haskell development? 564 | 565 | If you want to use Nix for Haskell development, I recommend reading the 566 | resources below in the order they are listed: 567 | 568 | 1. [Nix Pills](https://nixos.org/nixos/nix-pills/) 569 | 570 | This is a long-form walk-through on how Nix works. It doesn't have 571 | anything directly to do with Haskell, but it brings you up to speed on Nix. 572 | 573 | This is quite long. Expect to spend 10 to 20 hours working through this. 574 | 575 | This may sound like a lot, but keep in mind that Nix is very similar to 576 | Haskell. If you are a Haskell beginner (and Haskell is your first 577 | statically-typed functional language), you can't dive right into writing web 578 | apps. Instead, you have to slowly and methodically study the language. 579 | After you have enough of the beginner-level info under your belt, then you 580 | can work on harder things like web apps. Nix is the same. 581 | 582 | 2. [Gabriel Gonzalez's haskell-nix walk-through](https://github.com/Gabriel439/haskell-nix) 583 | 584 | This more-or-less takes up from where the Nix Pills leave off. It is a 585 | beginner-oriented walk-through for how to use Nix for Haskell development. 586 | 587 | Personally, I don't like some of the decisions they made with how to 588 | present Nix for Haskell development, but it is currently the best 589 | beginner-oriented tutorial available. 590 | 591 | 3. [nixpkgs manual on Haskell development](https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure) 592 | 593 | As explained above, the nixpkgs manual has many problems. It is somewhat 594 | hard to understand unless you've already read the Nix Pills and Gabriel's 595 | intro. 596 | 597 | 4. [Nix manual](https://nixos.org/nix/manual/) and [nixpkgs manual](https://nixos.org/nixpkgs/manual/) 598 | 599 | These are not required reading, but you may want to skim through them. The 600 | more you understand Nix, the more helpful the manuals become. 601 | 602 | Once you've read the first three resources (and possibly the fourth), you 603 | should be ready to start using Nix for Haskell development. 604 | 605 | I recommend disregarding the advice from both the haskell-nix walk-through and 606 | the nixpkgs manual. Instead, you should setup your repos similar to how the 607 | [example repo](https://github.com/cdepillabout/nix-cabal-example-project) is 608 | structured. 609 | 610 | For larger projects, you should use a tool like 611 | [`haskell.nix`](https://github.com/input-output-hk/haskell.nix) or 612 | [`stack2nix`](https://github.com/input-output-hk/stack2nix). 613 | 614 | ### 10. Should Haskell beginners learn Nix? 615 | 616 | **No**. 617 | 618 | If your goal is to learn Haskell, you can get by just fine with `stack` or 619 | `cabal`.[^9] Nix requires a large upfront investment in time, and it doesn't 620 | directly help you on your quest to learn Haskell. You should stay away from 621 | Nix, at least for now. 622 | 623 | If you are an intermediate to advanced Haskeller and are looking for a powerful 624 | and flexible way to deal with dependencies, then investigating Nix might be a 625 | good choice. 626 | 627 | If you're not particularly interested in Haskell, but are looking for a novel 628 | Linux package manager, then checkout Nix! 629 | 630 | ## Conclusion 631 | 632 | Nix can be nice to use for Haskell development. Being so flexible, it provides 633 | many different ways to integrate with common Haskell tools. However, it has a 634 | steep learning curve, so the decision to plunge head-first into Nix should not 635 | be made lightly. 636 | 637 | ## Footnotes 638 | 639 | [^1]: This example has been simplified. It won't work as-is. If 640 | you're interested in playing around with this, I recommend you read the 641 | relevant section in the 642 | [Nix manual](https://nixos.org/nix/manual/#ch-simple-expression). 643 | 644 | [^2]: This quite a big simplification of what actually happens, but it is a 645 | reasonable first approximation. 646 | 647 | [^3]: Again, this won't actually work as-is. It is mostly to show the relation 648 | between the Nix language derivations, and the Nix CLI tools. If you're 649 | interested in actually learning to build your own derivations, I recommend 650 | reading through the informative 651 | [Nix Pills](https://nixos.org/nixos/nix-pills/). 652 | 653 | [^4]: One of my friends, [Dave Della Costa](http://davedellacosta.com/), wrote 654 | an article about 655 | [getting into Nix as a new user](http://davedellacosta.com/posts/2019-03-29-why-nixos-is-hard-and-how-to-fix.html) 656 | He talks about what makes Nix difficult for a new user. I strongly agree 657 | with most of the points he makes. 658 | 659 | [^5]: For the most part, it only duplicates the information important 660 | for figuring out the dependencies of `conduit`. For instance, `conduit` 661 | depends on the `resourcet` Haskell package. When trying to build the 662 | `conduit` derivation, the Nix CLI tools need to know that first the 663 | `resourcet` derivation should be built. 664 | 665 | [^6]: The `Cabal` library is used directly by the build process internally. 666 | 667 | [^7]: Some of the questions are from me, not Dmitrii. I added them to try to 668 | make this article easier to read from top to bottom without needing to 669 | jump around. 670 | 671 | [^8]: This isn't completely true. The actual setup is a little more complex. 672 | 673 | nixpkgs generally tracks the most recent Stackage LTS release. At the time 674 | of this writing, the most recent Stackage LTS release is LTS-13.30. This 675 | contains, for example, 676 | [`servant-0.15`](https://www.stackage.org/lts-13.30/package/servant-0.15), 677 | even though the most recent release on Hackage is 678 | [`servant-0.16.1`](https://hackage.haskell.org/package/servant-0.16.1). 679 | 680 | The `servant` derivation in nixpkgs currently refers to `servant-0.15`. However, 681 | there is also a separate derivation called `servant_0_16_1` that refers to 682 | `servant-0.16.1`. 683 | 684 | The reason that nixpkgs tracks the most recent Stackage LTS release, and 685 | not the latest current version on Hackage, is to hopefully increase the 686 | number of Haskell packages that successfully compile with each other. 687 | 688 | [^9]: I'd recommend `stack` over `cabal` for most beginners. `stack` is often 689 | easier to get things working. 690 | 691 | However, some people strongly dislike `stack` and swear by `cabal`. Your 692 | mileage may vary. 693 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdepillabout/post-about-nix-and-haskell/39270c7085c8299690af9c3dfe27c4367797a097/README.md --------------------------------------------------------------------------------