lib.fixedPoints.extends: Improve documentation

The previous one was unnecessarily confusing.
This commit is contained in:
Silvan Mosberger 2023-08-09 23:41:22 +02:00
parent 697d536087
commit 8585568d7d

View File

@ -53,39 +53,60 @@ rec {
else converge f x'; else converge f x';
/* /*
Modify the contents of an explicitly recursive attribute set in a way that `extends overlay f` applies the overlay `overlay` to the fixed-point function `f` to get a new fixed-point function.
honors `self`-references. This is accomplished with a function Overlays allow modifying and extending fixed-point functions, specifically ones returning attribute sets.
```nix A fixed-point function is a function which is intended to be evaluated by passing the result of itself as the argument, only possible due to Nix's lazy evaluation.
g = self: super: { foo = super.foo + " + "; } Here's an example of one:
```
f = final: {
# Constant value a
a = 1;
# b depends on the final value of a, available as final.a
b = final.a + 2;
}
```
We can evaluated this using [`lib.fix`](#function-library-lib.fixedPoints.fix) to get the final result:
```
fix f
=> { a = 1; b = 3; }
``` ```
that has access to the unmodified input (`super`) as well as the final An overlay represents a modification or extension of such a fixed-point function.
non-recursive representation of the attribute set (`self`). `extends` Here's an example of an overlay:
differs from the native `//` operator insofar as that it's applied *before*
references to `self` are resolved:
``` ```
nix-repl> fix (extends g f) overlay = final: prev: {
{ bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } # Modify the previous value of a, available as prev.a
a = prev.a + 10;
# Extend the attribute set with c, letting it depend on the final values of a and b
c = final.a + final.b;
}
``` ```
The name of the function is inspired by object-oriented inheritance, i.e. We can now use `extends overlay f` to apply the overlay to the fixed-point function `f`, giving us a new fixed-point function `g` with the combined behavior of `f` and `overlay`.
think of it as an infix operator `g extends f` that mimics the syntax from
Java. It may seem counter-intuitive to have the "base class" as the second
argument, but it's nice this way if several uses of `extends` are cascaded.
To get a better understanding how `extends` turns a function with a fix
point (the package set we start with) into a new function with a different fix
point (the desired packages set) lets just see, how `extends g f`
unfolds with `g` and `f` defined above:
``` ```
extends g f = self: let super = f self; in super // g self super; g = extends overlay f
= self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super ```
= self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } The result is a function, so we can't print it directly, but it's the same as:
= self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } ```
= self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } g = final: {
# The constant from f, but changed with the overlay
a = 1 + 10;
# Unchanged from f
b = final.a + 2;
# Extended in the overlay
c = final.a + final.b;
}
```
We can evaluate this using [`lib.fix`](#function-library-lib.fixedPoints.fix) again to get the final result:
```
fix g
=> { a = 11; b = 13; c = 24; }
``` ```
*/ */
extends = f: rattrs: self: let super = rattrs self; in super // f self super; extends = f: rattrs: self: let super = rattrs self; in super // f self super;