doc: lib.composeExtensions reference to overlays (#325479)
This commit is contained in:
commit
b4292c4370
@ -63,7 +63,6 @@ rec {
|
|||||||
See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case.
|
See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case.
|
||||||
There `self` is also often called `final`.
|
There `self` is also often called `final`.
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
# Inputs
|
||||||
|
|
||||||
`f`
|
`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
|
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
|
This is useful in combination with the `extends` function to
|
||||||
implement deep overriding.
|
implement deep overriding.
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
# Inputs
|
||||||
|
|
||||||
`f`
|
`f`
|
||||||
|
|
||||||
: 1\. Function argument
|
: 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
|
Return the fixpoint that `f` converges to when called iteratively, starting
|
||||||
@ -117,7 +127,6 @@ rec {
|
|||||||
0
|
0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
# Inputs
|
||||||
|
|
||||||
`f`
|
`f`
|
||||||
@ -134,13 +143,12 @@ rec {
|
|||||||
(a -> a) -> a -> a
|
(a -> a) -> a -> a
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
converge = f: x:
|
converge =
|
||||||
|
f: x:
|
||||||
let
|
let
|
||||||
x' = f x;
|
x' = f x;
|
||||||
in
|
in
|
||||||
if x' == x
|
if x' == x then x else converge f x';
|
||||||
then x
|
|
||||||
else converge f x';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Extend a function using an overlay.
|
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.
|
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.
|
This is possible due to Nix's lazy evaluation.
|
||||||
|
|
||||||
|
|
||||||
A fixed-point function returning an attribute set has the form
|
A fixed-point function returning an attribute set has the form
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
@ -257,7 +264,6 @@ rec {
|
|||||||
```
|
```
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
# Inputs
|
||||||
|
|
||||||
`overlay`
|
`overlay`
|
||||||
@ -299,8 +305,7 @@ rec {
|
|||||||
:::
|
:::
|
||||||
*/
|
*/
|
||||||
extends =
|
extends =
|
||||||
overlay:
|
overlay: f:
|
||||||
f:
|
|
||||||
# The result should be thought of as a function, the argument of that function is not an argument to `extends` itself
|
# The result should be thought of as a function, the argument of that function is not an argument to `extends` itself
|
||||||
(
|
(
|
||||||
final:
|
final:
|
||||||
@ -311,63 +316,98 @@ rec {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compose two extending functions of the type expected by 'extends'
|
Compose two overlay functions and return a single overlay function that combines them.
|
||||||
into one where changes made in the first are available in the
|
For more details see: [composeManyExtensions](#function-library-lib.fixedPoints.composeManyExtensions).
|
||||||
'super' of the second
|
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
|
||||||
|
|
||||||
`f`
|
|
||||||
|
|
||||||
: 1\. Function argument
|
|
||||||
|
|
||||||
`g`
|
|
||||||
|
|
||||||
: 2\. Function argument
|
|
||||||
|
|
||||||
`final`
|
|
||||||
|
|
||||||
: 3\. Function argument
|
|
||||||
|
|
||||||
`prev`
|
|
||||||
|
|
||||||
: 4\. Function argument
|
|
||||||
*/
|
*/
|
||||||
composeExtensions =
|
composeExtensions =
|
||||||
f: g: final: prev:
|
f: g: final: prev:
|
||||||
let fApplied = f final prev;
|
let
|
||||||
prev' = prev // fApplied;
|
fApplied = f final prev;
|
||||||
in fApplied // g final prev';
|
prev' = prev // fApplied;
|
||||||
|
in
|
||||||
|
fApplied // g final prev';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compose several extending functions of the type expected by 'extends' into
|
Composes a list of [`overlays`](#chap-overlays) and returns a single overlay function that combines them.
|
||||||
one where changes made in preceding functions are made available to
|
|
||||||
subsequent ones.
|
:::{.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
|
# Pseudo code
|
||||||
^final ^prev ^overrides ^final ^prev ^overrides
|
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 =
|
composeManyExtensions = lib.foldr (x: y: composeExtensions x y) (final: prev: { });
|
||||||
lib.foldr (x: y: composeExtensions x y) (final: prev: {});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create an overridable, recursive attribute set. For example:
|
Create an overridable, recursive attribute set. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
nix-repl> obj = makeExtensible (self: { })
|
nix-repl> obj = makeExtensible (final: { })
|
||||||
|
|
||||||
nix-repl> obj
|
nix-repl> obj
|
||||||
{ __unfix__ = «lambda»; extend = «lambda»; }
|
{ __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
|
nix-repl> obj
|
||||||
{ __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
|
{ __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
|
nix-repl> obj
|
||||||
{ __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
|
{ __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
|
Same as `makeExtensible` but the name of the extending attribute is
|
||||||
customized.
|
customized.
|
||||||
|
|
||||||
|
|
||||||
# Inputs
|
# Inputs
|
||||||
|
|
||||||
`extenderName`
|
`extenderName`
|
||||||
@ -390,8 +429,13 @@ rec {
|
|||||||
|
|
||||||
: 2\. Function argument
|
: 2\. Function argument
|
||||||
*/
|
*/
|
||||||
makeExtensibleWithCustomName = extenderName: rattrs:
|
makeExtensibleWithCustomName =
|
||||||
fix' (self: (rattrs self) // {
|
extenderName: rattrs:
|
||||||
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
|
fix' (
|
||||||
});
|
self:
|
||||||
|
(rattrs self)
|
||||||
|
// {
|
||||||
|
${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user