Skip to content

Commit

Permalink
lib.lists.foldl': Make strict in the initial accumulator
Browse files Browse the repository at this point in the history
To maintain backwards compatibility, this can't be changed in the Nix language.
We can however ensure that the version Nixpkgs has the more intuitive behavior.
  • Loading branch information
infinisil committed Sep 27, 2023
1 parent 857a844 commit 3b6169f
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 6 deletions.
2 changes: 1 addition & 1 deletion lib/attrsets.nix
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ rec {
foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
*/
foldlAttrs = f: init: set:
foldl'
builtins.foldl'
(acc: name: f acc name set.${name})
init
(attrNames set);
Expand Down
13 changes: 10 additions & 3 deletions lib/lists.nix
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,12 @@ rec {
Reduce a list by applying a binary operator from left to right,
starting with an initial accumulator.
After each application of the operator, the resulting value is evaluated.
Before each application of the operator, the accumulator value is evaluated.
This behavior makes this function stricter than [`foldl`](#function-library-lib.lists.foldl).
Unlike [`builtins.foldl'`](https://nixos.org/manual/nix/unstable/language/builtins.html#builtins-foldl'),
the initial accumulator argument is evaluated before the first iteration.
A call like
```nix
Expand All @@ -104,7 +107,7 @@ rec {
```nix
let
acc₁ = op acc₀ x₀ ;
acc₁ = builtins.seq acc₀ (op acc₀ x₀ );
acc₂ = builtins.seq acc₁ (op acc₁ x₁ );
acc₃ = builtins.seq acc₂ (op acc₂ x₂ );
...
Expand Down Expand Up @@ -135,7 +138,11 @@ rec {
# The list to fold
list:

builtins.foldl' op acc list;
# The builtin `foldl'` is a bit lazier than one might expect.
# See https://github.com/NixOS/nix/pull/7158.
# In particular, the initial accumulator value is not forced before the first iteration starts.
builtins.seq acc
(builtins.foldl' op acc list);

/* Map with index starting from 0
Expand Down
4 changes: 2 additions & 2 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -524,10 +524,10 @@ runTests {
expected = [ 3 2 1 ];
};

# The same as builtins.foldl', lib.foldl' doesn't evaluate the first accumulator strictly
# Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
testFoldl'StrictInitial = {
expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
expected = true;
expected = false;
};

# Make sure we don't get a stack overflow for large lists
Expand Down
3 changes: 3 additions & 0 deletions nixos/doc/manual/release-notes/rl-2311.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@

- `networking.networkmanager.firewallBackend` was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally.

- [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl-prime) now always evaluates the initial accumulator argument first.
If you depend on the lazier behavior, consider using [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl) or [`builtins.foldl'`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl') instead.

- `rome` was removed because it is no longer maintained and is succeeded by `biome`.

- The `services.mtr-exporter.target` has been removed in favor of `services.mtr-exporter.jobs` which allows specifying multiple targets.
Expand Down

0 comments on commit 3b6169f

Please sign in to comment.