forked from mirrors/nixpkgs
Provide O(n) time implementations of fold/foldl/any/all
Previous implementations were O(n^2) because tail takes O(n) time.
This commit is contained in:
parent
c0a483632c
commit
c68c95d55a
|
@ -1,7 +1,7 @@
|
||||||
# General list operations.
|
# General list operations.
|
||||||
|
|
||||||
rec {
|
rec {
|
||||||
inherit (builtins) head tail length isList;
|
inherit (builtins) elemAt head tail length isList add sub lessThan;
|
||||||
|
|
||||||
|
|
||||||
# Create a list consisting of a single element. `singleton x' is
|
# Create a list consisting of a single element. `singleton x' is
|
||||||
|
@ -14,18 +14,44 @@ rec {
|
||||||
# `list' with `nul' as the starting value, i.e., `fold op nul [x_1
|
# `list' with `nul' as the starting value, i.e., `fold op nul [x_1
|
||||||
# x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))'. (This is
|
# x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))'. (This is
|
||||||
# Haskell's foldr).
|
# Haskell's foldr).
|
||||||
fold = op: nul: list:
|
fold =
|
||||||
|
if builtins ? elemAt
|
||||||
|
then op: nul: list:
|
||||||
|
let
|
||||||
|
len = length list;
|
||||||
|
fold' = n:
|
||||||
|
if n == len
|
||||||
|
then nul
|
||||||
|
else op (elemAt list n) (fold' (add n 1));
|
||||||
|
in fold' 0
|
||||||
|
else op: nul:
|
||||||
|
let fold' = list:
|
||||||
if list == []
|
if list == []
|
||||||
then nul
|
then nul
|
||||||
else op (head list) (fold op nul (tail list));
|
else op (head list) (fold' (tail list));
|
||||||
|
in fold';
|
||||||
|
|
||||||
|
|
||||||
# Left fold: `fold op nul [x_1 x_2 ... x_n] == op (... (op (op nul
|
# Left fold: `fold op nul [x_1 x_2 ... x_n] == op (... (op (op nul
|
||||||
# x_1) x_2) ... x_n)'.
|
# x_1) x_2) ... x_n)'.
|
||||||
foldl = op: nul: list:
|
foldl =
|
||||||
|
if builtins ? elemAt
|
||||||
|
then op: nul: list:
|
||||||
|
let
|
||||||
|
len = length list;
|
||||||
|
foldl' = n:
|
||||||
|
if n == minus1
|
||||||
|
then nul
|
||||||
|
else op (foldl' (sub n 1)) (elemAt list n);
|
||||||
|
in foldl' (sub (length list) 1)
|
||||||
|
else op:
|
||||||
|
let foldl' = nul: list:
|
||||||
if list == []
|
if list == []
|
||||||
then nul
|
then nul
|
||||||
else foldl op (op nul (head list)) (tail list);
|
else foldl' (op nul (head list)) (tail list);
|
||||||
|
in foldl';
|
||||||
|
|
||||||
|
minus1 = sub 0 1;
|
||||||
|
|
||||||
|
|
||||||
# map with index: `imap (i: v: "${v}-${toString i}") ["a" "b"] ==
|
# map with index: `imap (i: v: "${v}-${toString i}") ["a" "b"] ==
|
||||||
|
@ -92,18 +118,12 @@ rec {
|
||||||
|
|
||||||
# Return true iff function `pred' returns true for at least element
|
# Return true iff function `pred' returns true for at least element
|
||||||
# of `list'.
|
# of `list'.
|
||||||
any = pred: list:
|
any = pred: fold (x: y: if pred x then true else y) false;
|
||||||
if list == [] then false
|
|
||||||
else if pred (head list) then true
|
|
||||||
else any pred (tail list);
|
|
||||||
|
|
||||||
|
|
||||||
# Return true iff function `pred' returns true for all elements of
|
# Return true iff function `pred' returns true for all elements of
|
||||||
# `list'.
|
# `list'.
|
||||||
all = pred: list:
|
all = pred: fold (x: y: if pred x then y else false) true;
|
||||||
if list == [] then true
|
|
||||||
else if pred (head list) then all pred (tail list)
|
|
||||||
else false;
|
|
||||||
|
|
||||||
|
|
||||||
# Return true if each element of a list is equal, false otherwise.
|
# Return true if each element of a list is equal, false otherwise.
|
||||||
|
|
Loading…
Reference in a new issue