3
0
Fork 0
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:
Eelco Dolstra 2012-08-13 14:19:50 -04:00
parent c0a483632c
commit c68c95d55a

View file

@ -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.