summaryrefslogtreecommitdiffstats
path: root/lib/lists.nix
diff options
context:
space:
mode:
authorzimbatm <zimbatm@zimbatm.com>2016-02-28 23:27:06 +0000
committerzimbatm <zimbatm@zimbatm.com>2016-03-10 12:31:05 +0000
commitc71e2d42359f9900ea2c290d141c0d606471da16 (patch)
treeac6f564d231a1be28a61eb2231ee50f2d25008d3 /lib/lists.nix
parent523e3283189710a9a58bd2828f45a7413f3ede3e (diff)
lib/lists: document all functions
Diffstat (limited to 'lib/lists.nix')
-rw-r--r--lib/lists.nix272
1 files changed, 217 insertions, 55 deletions
diff --git a/lib/lists.nix b/lib/lists.nix
index 9e4ab9e2d95d..deb7dcfde428 100644
--- a/lib/lists.nix
+++ b/lib/lists.nix
@@ -6,17 +6,26 @@ rec {
inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
-
- # Create a list consisting of a single element. `singleton x' is
- # sometimes more convenient with respect to indentation than `[x]'
- # when x spans multiple lines.
+ /* Create a list consisting of a single element. `singleton x' is
+ sometimes more convenient with respect to indentation than `[x]'
+ when x spans multiple lines.
+
+ Example:
+ singleton "foo"
+ => [ "foo" ]
+ */
singleton = x: [x];
+ /* "Fold" a binary function `op' between successive elements of
+ `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
+ Haskell's foldr).
- # "Fold" a binary function `op' between successive elements of
- # `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
- # Haskell's foldr).
+ Example:
+ concat = fold (a: b: a + b) "z"
+ concat [ "a" "b" "c" ]
+ => "abcnul"
+ */
fold = op: nul: list:
let
len = length list;
@@ -26,8 +35,14 @@ rec {
else op (elemAt list n) (fold' (n + 1));
in fold' 0;
- # Left fold: `fold op nul [x_1 x_2 ... x_n] == op (... (op (op nul
- # x_1) x_2) ... x_n)'.
+ /* Left fold: `fold op nul [x_1 x_2 ... x_n] == op (... (op (op nul
+ x_1) x_2) ... x_n)'.
+
+ Example:
+ lconcat = foldl (a: b: a + b) "z"
+ lconcat [ "a" "b" "c" ]
+ => "zabc"
+ */
foldl = op: nul: list:
let
len = length list;
@@ -37,13 +52,22 @@ rec {
else op (foldl' (n - 1)) (elemAt list n);
in foldl' (length list - 1);
+ /* Strict version of foldl.
- # Strict version of foldl.
+ The difference is that evaluation is forced upon access. Usually used
+ with small whole results (in contract with lazily-generated list or large
+ lists where only a part is consumed.)
+ */
foldl' = builtins.foldl' or foldl;
+ /* Map with index
+
+ FIXME(zimbatm): why does this start to count at 1?
- # Map with index: `imap (i: v: "${v}-${toString i}") ["a" "b"] ==
- # ["a-1" "b-2"]'. FIXME: why does this start to count at 1?
+ Example:
+ imap (i: v: "${v}-${toString i}") ["a" "b"]
+ => [ "a-1" "b-2" ]
+ */
imap =
if builtins ? genList then
f: list: genList (n: f (n + 1) (elemAt list n)) (length list)
@@ -57,73 +81,141 @@ rec {
else [ (f (n + 1) (elemAt list n)) ] ++ imap' (n + 1);
in imap' 0;
+ /* Map and concatenate the result.
- # Map and concatenate the result.
+ Example:
+ concatMap (x: [x] ++ ["z"]) ["a" "b"]
+ => [ "a" "z" "b" "z" ]
+ */
concatMap = f: list: concatLists (map f list);
+ /* Flatten the argument into a single list; that is, nested lists are
+ spliced into the top-level lists.
- # Flatten the argument into a single list; that is, nested lists are
- # spliced into the top-level lists. E.g., `flatten [1 [2 [3] 4] 5]
- # == [1 2 3 4 5]' and `flatten 1 == [1]'.
+ Example:
+ flatten [1 [2 [3] 4] 5]
+ => [1 2 3 4 5]
+ flatten 1
+ => [1]
+ */
flatten = x:
if isList x
then foldl' (x: y: x ++ (flatten y)) [] x
else [x];
+ /* Remove elements equal to 'e' from a list. Useful for buildInputs.
- # Remove elements equal to 'e' from a list. Useful for buildInputs.
+ Example:
+ remove 3 [ 1 3 4 3 ]
+ => [ 1 4 ]
+ */
remove = e: filter (x: x != e);
-
- # Find the sole element in the list matching the specified
- # predicate, returns `default' if no such element exists, or
- # `multiple' if there are multiple matching elements.
+ /* Find the sole element in the list matching the specified
+ predicate, returns `default' if no such element exists, or
+ `multiple' if there are multiple matching elements.
+
+ Example:
+ findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
+ => "multiple"
+ findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
+ => 3
+ findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
+ => "none"
+ */
findSingle = pred: default: multiple: list:
let found = filter pred list; len = length found;
in if len == 0 then default
else if len != 1 then multiple
else head found;
+ /* Find the first element in the list matching the specified
+ predicate or returns `default' if no such element exists.
- # Find the first element in the list matching the specified
- # predicate or returns `default' if no such element exists.
+ Example:
+ findFirst (x: x > 3) 7 [ 1 6 4 ]
+ => 6
+ findFirst (x: x > 9) 7 [ 1 6 4 ]
+ => 7
+ */
findFirst = pred: default: list:
let found = filter pred list;
in if found == [] then default else head found;
+ /* Return true iff function `pred' returns true for at least element
+ of `list'.
- # Return true iff function `pred' returns true for at least element
- # of `list'.
+ Example:
+ any isString [ 1 "a" { } ]
+ => true
+ any isString [ 1 { } ]
+ => false
+ */
any = builtins.any or (pred: fold (x: y: if pred x then true else y) false);
+ /* Return true iff function `pred' returns true for all elements of
+ `list'.
- # Return true iff function `pred' returns true for all elements of
- # `list'.
+ Example:
+ all (x: x < 3) [ 1 2 ]
+ => true
+ all (x: x < 3) [ 1 2 3 ]
+ => false
+ */
all = builtins.all or (pred: fold (x: y: if pred x then y else false) true);
+ /* Count how many times function `pred' returns true for the elements
+ of `list'.
- # Count how many times function `pred' returns true for the elements
- # of `list'.
+ Example:
+ count (x: x == 3) [ 3 2 3 4 6 ]
+ => 2
+ */
count = pred: foldl' (c: x: if pred x then c + 1 else c) 0;
+ /* Return a singleton list or an empty list, depending on a boolean
+ value. Useful when building lists with optional elements
+ (e.g. `++ optional (system == "i686-linux") flashplayer').
- # Return a singleton list or an empty list, depending on a boolean
- # value. Useful when building lists with optional elements
- # (e.g. `++ optional (system == "i686-linux") flashplayer').
+ Example:
+ optional true "foo"
+ => [ "foo" ]
+ optional false "foo"
+ => [ ]
+ */
optional = cond: elem: if cond then [elem] else [];
+ /* Return a list or an empty list, dependening on a boolean value.
- # Return a list or an empty list, dependening on a boolean value.
+ Example:
+ optionals true [ 2 3 ]
+ => [ 2 3 ]
+ optionals false [ 2 3 ]
+ => [ ]
+ */
optionals = cond: elems: if cond then elems else [];
- # If argument is a list, return it; else, wrap it in a singleton
- # list. If you're using this, you should almost certainly
- # reconsider if there isn't a more "well-typed" approach.
+ /* If argument is a list, return it; else, wrap it in a singleton
+ list. If you're using this, you should almost certainly
+ reconsider if there isn't a more "well-typed" approach.
+
+ Example:
+ toList [ 1 2 ]
+ => [ 1 2 ]
+ toList "hi"
+ => [ "hi "]
+ */
toList = x: if isList x then x else [x];
+ /* Return a list of integers from `first' up to and including `last'.
- # Return a list of integers from `first' up to and including `last'.
+ Example:
+ range 2 4
+ => [ 2 3 4 ]
+ range 3 2
+ => [ ]
+ */
range =
if builtins ? genList then
first: last:
@@ -136,9 +228,13 @@ rec {
then []
else [first] ++ range (first + 1) last;
+ /* Splits the elements of a list in two lists, `right' and
+ `wrong', depending on the evaluation of a predicate.
- # Partition the elements of a list in two lists, `right' and
- # `wrong', depending on the evaluation of a predicate.
+ Example:
+ partition (x: x > 2) [ 5 1 2 3 4 ]
+ => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
+ */
partition = pred:
fold (h: t:
if pred h
@@ -146,7 +242,14 @@ rec {
else { right = t.right; wrong = [h] ++ t.wrong; }
) { right = []; wrong = []; };
+ /* Merges two lists of the same size together. If the sizes aren't the same
+ the merging stops at the shortest. How both lists are merged is defined
+ by the first argument.
+ Example:
+ zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
+ => ["he" "lo"]
+ */
zipListsWith =
if builtins ? genList then
f: fst: snd: genList (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd))
@@ -161,21 +264,37 @@ rec {
else [];
in zipListsWith' 0;
+ /* Merges two lists of the same size together. If the sizes aren't the same
+ the merging stops at the shortest.
+
+ Example:
+ zipLists [ 1 2 ] [ "a" "b" ]
+ => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
+ */
zipLists = zipListsWith (fst: snd: { inherit fst snd; });
+ /* Reverse the order of the elements of a list.
- # Reverse the order of the elements of a list.
+ Example:
+
+ reverseList [ "b" "o" "j" ]
+ => [ "j" "o" "b" ]
+ */
reverseList =
if builtins ? genList then
xs: let l = length xs; in genList (n: elemAt xs (l - n - 1)) l
else
fold (e: acc: acc ++ [ e ]) [];
+ /* Sort a list based on a comparator function which compares two
+ elements and returns true if the first argument is strictly below
+ the second argument. The returned list is sorted in an increasing
+ order. The implementation does a quick-sort.
- # Sort a list based on a comparator function which compares two
- # elements and returns true if the first argument is strictly below
- # the second argument. The returned list is sorted in an increasing
- # order. The implementation does a quick-sort.
+ Example:
+ sort (a: b: a < b) [ 5 3 7 ]
+ => [ 3 5 7 ]
+ */
sort = builtins.sort or (
strictLess: list:
let
@@ -193,8 +312,14 @@ rec {
if len < 2 then list
else (sort strictLess pivot.left) ++ [ first ] ++ (sort strictLess pivot.right));
+ /* Return the first (at most) N elements of a list.
- # Return the first (at most) N elements of a list.
+ Example:
+ take 2 [ "a" "b" "c" "d" ]
+ => [ "a" "b" ]
+ take 2 [ ]
+ => [ ]
+ */
take =
if builtins ? genList then
count: sublist 0 count
@@ -209,8 +334,14 @@ rec {
[ (elemAt list n) ] ++ take' (n + 1);
in take' 0;
+ /* Remove the first (at most) N elements of a list.
- # Remove the first (at most) N elements of a list.
+ Example:
+ drop 2 [ "a" "b" "c" "d" ]
+ => [ "c" "d" ]
+ drop 2 [ ]
+ => [ ]
+ */
drop =
if builtins ? genList then
count: list: sublist count (length list) list
@@ -225,9 +356,15 @@ rec {
drop' (n - 1) ++ [ (elemAt list n) ];
in drop' (len - 1);
+ /* Return a list consisting of at most ‘count’ elements of ‘list’,
+ starting at index ‘start’.
- # Return a list consisting of at most ‘count’ elements of ‘list’,
- # starting at index ‘start’.
+ Example:
+ sublist 1 3 [ "a" "b" "c" "d" "e" ]
+ => [ "b" "c" "d" ]
+ sublist 1 3 [ ]
+ => [ ]
+ */
sublist = start: count: list:
let len = length list; in
genList
@@ -236,20 +373,36 @@ rec {
else if start + count > len then len - start
else count);
+ /* Return the last element of a list.
- # Return the last element of a list.
+ Example:
+ last [ 1 2 3 ]
+ => 3
+ */
last = list:
assert list != []; elemAt list (length list - 1);
+ /* Return all elements but the last
- # Return all elements but the last
+ Example:
+ init [ 1 2 3 ]
+ => [ 1 2 ]
+ */
init = list: assert list != []; take (length list - 1) list;
+ /* FIXME(zimbatm) Not used anywhere
+ */
crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [f];
- # Remove duplicate elements from the list. O(n^2) complexity.
+ /* Remove duplicate elements from the list. O(n^2) complexity.
+
+ Example:
+
+ unique [ 3 2 3 4 ]
+ => [ 3 2 4 ]
+ */
unique = list:
if list == [] then
[]
@@ -259,15 +412,24 @@ rec {
xs = unique (drop 1 list);
in [x] ++ remove x xs;
+ /* Intersects list 'e' and another list. O(nm) complexity.
- # Intersects list 'e' and another list. O(nm) complexity.
+ Example:
+ intersectLists [ 1 2 3 ] [ 6 3 2 ]
+ => [ 3 2 ]
+ */
intersectLists = e: filter (x: elem x e);
+ /* Subtracts list 'e' from another list. O(nm) complexity.
- # Subtracts list 'e' from another list. O(nm) complexity.
+ Example:
+ subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
+ => [ 1 4 5 ]
+ */
subtractLists = e: filter (x: !(elem x e));
- deepSeqList = throw "removed 2016-02-29 because unused and broken";
+ /*** deprecated stuff ***/
+ deepSeqList = throw "removed 2016-02-29 because unused and broken";
}