init: lib.foldlAttrs
- provide comprehensive example - add unit test
This commit is contained in:
parent
624432c25b
commit
15a8d05ba5
@ -333,6 +333,66 @@ rec {
|
||||
) (attrNames set)
|
||||
);
|
||||
|
||||
/*
|
||||
Like builtins.foldl' but for attribute sets.
|
||||
Iterates over every name-value pair in the given attribute set.
|
||||
The result of the callback function is often called `acc` for accumulator. It is passed between callbacks from left to right and the final `acc` is the return value of `foldlAttrs`.
|
||||
|
||||
Attention:
|
||||
There is a completely different function
|
||||
`lib.foldAttrs`
|
||||
which has nothing to do with this function, despite the similar name.
|
||||
|
||||
Example:
|
||||
foldlAttrs
|
||||
(acc: name: value: {
|
||||
sum = acc.sum + value;
|
||||
names = acc.names ++ [name];
|
||||
})
|
||||
{ sum = 0; names = []; }
|
||||
{
|
||||
foo = 1;
|
||||
bar = 10;
|
||||
}
|
||||
->
|
||||
{
|
||||
sum = 11;
|
||||
names = ["bar" "foo"];
|
||||
}
|
||||
|
||||
foldlAttrs
|
||||
(throw "function not needed")
|
||||
123
|
||||
{};
|
||||
->
|
||||
123
|
||||
|
||||
foldlAttrs
|
||||
(_: _: v: v)
|
||||
(throw "initial accumulator not needed")
|
||||
{ z = 3; a = 2; };
|
||||
->
|
||||
3
|
||||
|
||||
The accumulator doesn't have to be an attrset.
|
||||
It can be as simple as a number or string.
|
||||
|
||||
foldlAttrs
|
||||
(acc: _: v: acc * 10 + v)
|
||||
1
|
||||
{ z = 1; a = 2; };
|
||||
->
|
||||
121
|
||||
|
||||
Type:
|
||||
foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
|
||||
*/
|
||||
foldlAttrs = f: init: set:
|
||||
foldl'
|
||||
(acc: name: f acc name set.${name})
|
||||
init
|
||||
(attrNames set);
|
||||
|
||||
/* Apply fold functions to values grouped by key.
|
||||
|
||||
Example:
|
||||
|
@ -78,7 +78,7 @@ let
|
||||
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
|
||||
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
|
||||
getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
|
||||
filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs
|
||||
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
|
||||
mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond
|
||||
genAttrs isDerivation toDerivation optionalAttrs
|
||||
zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
|
||||
|
@ -533,6 +533,37 @@ runTests {
|
||||
};
|
||||
};
|
||||
|
||||
# code from example
|
||||
testFoldlAttrs = {
|
||||
expr = {
|
||||
example = foldlAttrs
|
||||
(acc: name: value: {
|
||||
sum = acc.sum + value;
|
||||
names = acc.names ++ [ name ];
|
||||
})
|
||||
{ sum = 0; names = [ ]; }
|
||||
{
|
||||
foo = 1;
|
||||
bar = 10;
|
||||
};
|
||||
# should just return the initial value
|
||||
emptySet = foldlAttrs (throw "function not needed") 123 { };
|
||||
# should just evaluate to the last value
|
||||
accNotNeeded = foldlAttrs (_acc: _name: v: v) (throw "accumulator not needed") { z = 3; a = 2; };
|
||||
# the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
|
||||
trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
|
||||
};
|
||||
expected = {
|
||||
example = {
|
||||
sum = 11;
|
||||
names = [ "bar" "foo" ];
|
||||
};
|
||||
emptySet = 123;
|
||||
accNotNeeded = 3;
|
||||
trivialAcc = 121;
|
||||
};
|
||||
};
|
||||
|
||||
# code from the example
|
||||
testRecursiveUpdateUntil = {
|
||||
expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
|
||||
|
Loading…
Reference in New Issue
Block a user