rauhala.info/posts/configs.md
2019-03-27 22:26:48 +02:00

72 lines
2.3 KiB
Markdown

---
title: Extensible configuration Pt. 1
date: 2019-03-27
---
This is the first part of a series where I'm going through how to make
extensible configuration. There is nothing groundbreaking or new in this
series, it's just me going through different implementations and trying to
understand them.
The source material for this post is [the fixed point implementation](https://github.com/NixOS/nixpkgs/blob/master/lib/fixed-points.nix) for nix.
By extensible configuration, I'm talking about nix style extensible
configuration, like overlays, overrides and extensions. Let's see an example of
an extensible configuration.
``` nix
{ haskellPackages, fetchFromGitHub }:
let
purescript = fetchFromGitHub {
owner = "purescript";
repo = "purescript";
rev = "2cb4a6496052db726e099539be682b87585af494";
sha256 = "1v4gs08xnqgym6jj3drkzbic7ln3hfmflpbpij3qzwxsmqd2abr7";
}
hp = haskellPackages.extend (self: super: {
purescript = super.callCabal2nix "purescript" purescript {};
});
in
hp.purescript;
```
On a high level we are augmenting the `haskellPackages` attrset by replacing
the existing purescript package with a different one. The extension is a
function that takes two arguments, `self` and `super`. `super` is the original
non-lazy value and `self` is the lazy value that corresponds to the value at
end.
The first step on this journey is done by getting to know `fix`. Fix is
described being the least fixed point of a function. In practice it's a
function allowing declaring recursive functions without explicit recursion.
``` nix
fix = f: let x = f x; in x
```
With fix you can have access to the lazy `self` value. It's value is whatever
would have been computed in the end. As it is lazy, it is possible to end up in
a recursive loop if there is a cyclic dependency.
``` nix
let recursive = fix (self: {
foo = 3;
bar = self.foo + 1;
});
infinite = fix (self: {
foo = self.bar + 1;
bar = self.foo + 1;
});
```
You can try those yourself. The first version is fine and returns an attrset
like you would expect. The second one has a cyclic dependency and nix helpfully
errors out.
- https://elvishjerricco.github.io/2017/04/01/nix-style-configs-in-haskell.html
- https://github.com/NixOS/nixpkgs/blob/master/lib/fixed-points.nix
- https://chshersh.github.io/posts/2019-03-25-comonadic-builders