doc: lib.composeExtensions reference to overlays (#325479)

This commit is contained in:
Robert Hensing 2024-09-13 11:39:24 +02:00 committed by GitHub
commit b4292c4370
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -63,7 +63,6 @@ rec {
See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case.
There `self` is also often called `final`.
# Inputs
`f`
@ -90,7 +89,12 @@ rec {
:::
*/
fix = f: let x = f x; in x;
fix =
f:
let
x = f x;
in
x;
/**
A variant of `fix` that records the original recursive attribute set in the
@ -99,14 +103,20 @@ rec {
This is useful in combination with the `extends` function to
implement deep overriding.
# Inputs
`f`
: 1\. Function argument
*/
fix' = f: let x = f x // { __unfix__ = f; }; in x;
fix' =
f:
let
x = f x // {
__unfix__ = f;
};
in
x;
/**
Return the fixpoint that `f` converges to when called iteratively, starting
@ -117,7 +127,6 @@ rec {
0
```
# Inputs
`f`
@ -134,13 +143,12 @@ rec {
(a -> a) -> a -> a
```
*/
converge = f: x:
converge =
f: x:
let
x' = f x;
in
if x' == x
then x
else converge f x';
if x' == x then x else converge f x';
/**
Extend a function using an overlay.
@ -149,7 +157,6 @@ rec {
A fixed-point function is a function which is intended to be evaluated by passing the result of itself as the argument.
This is possible due to Nix's lazy evaluation.
A fixed-point function returning an attribute set has the form
```nix
@ -257,7 +264,6 @@ rec {
```
:::
# Inputs
`overlay`
@ -299,8 +305,7 @@ rec {
:::
*/
extends =
overlay:
f:
overlay: f:
# The result should be thought of as a function, the argument of that function is not an argument to `extends` itself
(
final:
@ -311,63 +316,98 @@ rec {
);
/**
Compose two extending functions of the type expected by 'extends'
into one where changes made in the first are available in the
'super' of the second
# Inputs
`f`
: 1\. Function argument
`g`
: 2\. Function argument
`final`
: 3\. Function argument
`prev`
: 4\. Function argument
Compose two overlay functions and return a single overlay function that combines them.
For more details see: [composeManyExtensions](#function-library-lib.fixedPoints.composeManyExtensions).
*/
composeExtensions =
f: g: final: prev:
let fApplied = f final prev;
prev' = prev // fApplied;
in fApplied // g final prev';
let
fApplied = f final prev;
prev' = prev // fApplied;
in
fApplied // g final prev';
/**
Compose several extending functions of the type expected by 'extends' into
one where changes made in preceding functions are made available to
subsequent ones.
Composes a list of [`overlays`](#chap-overlays) and returns a single overlay function that combines them.
:::{.note}
The result is produced by using the update operator `//`.
This means nested values of previous overlays are not merged recursively.
In other words, previously defined attributes are replaced, ignoring the previous value, unless referenced by the overlay; for example `final: prev: { foo = final.foo + 1; }`.
:::
# Inputs
`extensions`
: A list of overlay functions
:::{.note}
The order of the overlays in the list is important.
:::
: Each overlay function takes two arguments, by convention `final` and `prev`, and returns an attribute set.
- `final` is the result of the fixed-point function, with all overlays applied.
- `prev` is the result of the previous overlay function(s).
# Type
```
composeManyExtensions : [packageSet -> packageSet -> packageSet] -> packageSet -> packageSet -> packageSet
^final ^prev ^overrides ^final ^prev ^overrides
# Pseudo code
let
# final prev
# ↓ ↓
OverlayFn = { ... } -> { ... } -> { ... };
in
composeManyExtensions :: ListOf OverlayFn -> OverlayFn
```
# Examples
:::{.example}
## `lib.fixedPoints.composeManyExtensions` usage example
```nix
let
# The "original function" that is extended by the overlays.
# Note that it doesn't have prev: as argument since no overlay function precedes it.
original = final: { a = 1; };
# Each overlay function has 'final' and 'prev' as arguments.
overlayA = final: prev: { b = final.c; c = 3; };
overlayB = final: prev: { c = 10; x = prev.c or 5; };
extensions = composeManyExtensions [ overlayA overlayB ];
# Caluculate the fixed point of all composed overlays.
fixedpoint = lib.fix (lib.extends extensions original );
in fixedpoint
=>
{
a = 1;
b = 10;
c = 10;
x = 3;
}
```
:::
*/
composeManyExtensions =
lib.foldr (x: y: composeExtensions x y) (final: prev: {});
composeManyExtensions = lib.foldr (x: y: composeExtensions x y) (final: prev: { });
/**
Create an overridable, recursive attribute set. For example:
```
nix-repl> obj = makeExtensible (self: { })
nix-repl> obj = makeExtensible (final: { })
nix-repl> obj
{ __unfix__ = «lambda»; extend = «lambda»; }
nix-repl> obj = obj.extend (self: super: { foo = "foo"; })
nix-repl> obj = obj.extend (final: prev: { foo = "foo"; })
nix-repl> obj
{ __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; })
nix-repl> obj = obj.extend (final: prev: { foo = prev.foo + " + "; bar = "bar"; foobar = final.foo + final.bar; })
nix-repl> obj
{ __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
@ -379,7 +419,6 @@ rec {
Same as `makeExtensible` but the name of the extending attribute is
customized.
# Inputs
`extenderName`
@ -390,8 +429,13 @@ rec {
: 2\. Function argument
*/
makeExtensibleWithCustomName = extenderName: rattrs:
fix' (self: (rattrs self) // {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
});
makeExtensibleWithCustomName =
extenderName: rattrs:
fix' (
self:
(rattrs self)
// {
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
}
);
}