documentation: clarify genericClosure (#10003)

* doc: clarify genericClosure documentation

Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
This commit is contained in:
Johannes Kirschbauer 2024-02-24 19:34:53 +07:00 committed by GitHub
parent 0b47783d0a
commit d83008c3a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -705,38 +705,53 @@ static RegisterPrimOp primop_genericClosure(PrimOp {
.args = {"attrset"}, .args = {"attrset"},
.arity = 1, .arity = 1,
.doc = R"( .doc = R"(
Take an *attrset* with values named `startSet` and `operator` in order to `builtins.genericClosure` iteratively computes the transitive closure over an arbitrary relation defined by a function.
return a *list of attrsets* by starting with the `startSet` and recursively
applying the `operator` function to each `item`. The *attrsets* in the
`startSet` and the *attrsets* produced by `operator` must contain a value
named `key` which is comparable. The result is produced by calling `operator`
for each `item` with a value for `key` that has not been called yet including
newly produced `item`s. The function terminates when no new `item`s are
produced. The resulting *list of attrsets* contains only *attrsets* with a
unique key. For example,
``` It takes *attrset* with two attributes named `startSet` and `operator`, and returns a list of attrbute sets:
builtins.genericClosure {
startSet = [ {key = 5;} ]; - `startSet`:
operator = item: [{ The initial list of attribute sets.
key = if (item.key / 2 ) * 2 == item.key
then item.key / 2 - `operator`:
else 3 * item.key + 1; A function that takes an attribute set and returns a list of attribute sets.
}]; It defines how each item in the current set is processed and expanded into more items.
}
``` Each attribute set in the list `startSet` and the list returned by `operator` must have an attribute `key`, which must support equality comparison.
evaluates to The value of `key` can be one of the following types:
```
[ { key = 5; } { key = 16; } { key = 8; } { key = 4; } { key = 2; } { key = 1; } ]
```
`key` can be one of the following types:
- [Number](@docroot@/language/values.md#type-number) - [Number](@docroot@/language/values.md#type-number)
- [Boolean](@docroot@/language/values.md#type-boolean) - [Boolean](@docroot@/language/values.md#type-boolean)
- [String](@docroot@/language/values.md#type-string) - [String](@docroot@/language/values.md#type-string)
- [Path](@docroot@/language/values.md#type-path) - [Path](@docroot@/language/values.md#type-path)
- [List](@docroot@/language/values.md#list) - [List](@docroot@/language/values.md#list)
The result is produced by calling the `operator` on each `item` that has not been called yet, including newly added items, until no new items are added.
Items are compared by their `key` attribute.
Common usages are:
- Generating unique collections of items, such as dependency graphs.
- Traversing through structures that may contain cycles or loops.
- Processing data structures with complex internal relationships.
> **Example**
>
> ```nix
> builtins.genericClosure {
> startSet = [ {key = 5;} ];
> operator = item: [{
> key = if (item.key / 2 ) * 2 == item.key
> then item.key / 2
> else 3 * item.key + 1;
> }];
> }
> ```
>
> evaluates to
>
> ```nix
> [ { key = 5; } { key = 16; } { key = 8; } { key = 4; } { key = 2; } { key = 1; } ]
> ```
)", )",
.fun = prim_genericClosure, .fun = prim_genericClosure,
}); });