summary refs log tree commit diff
path: root/pkgs/lib/lists.nix
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2009-02-09 16:51:03 +0000
committerEelco Dolstra <eelco.dolstra@logicblox.com>2009-02-09 16:51:03 +0000
commit599015e8b071bc8d38779fbfc37961db1ac0f464 (patch)
tree12cfb8ef316f4021ef81d135a5c331804a817809 /pkgs/lib/lists.nix
parenteebb6f106c445c5661975a60a55b07ad91c6fa47 (diff)
downloadnixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar.gz
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar.bz2
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar.lz
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar.xz
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.tar.zst
nixpkgs-599015e8b071bc8d38779fbfc37961db1ac0f464.zip
* Split lib/default.nix into several files, as it had become a big
  mess.  Also cleaned up some functions:

  - foldl appeared broken (it recursively called fold).
  - Renamed logicalAND/logicalOR to and/or.
  - Removed listOfListsToAttrs, eqStrings: obsolete.
  - Removed isInList, which does the same thing as elem.
  - stringToCharacters: don't return a "" at the end of the list.
  - Renamed concatList to concat, as concatList (singular) is a
    misnomer: it takes two lists.  Likewise, renamed mergeAttr to
    mergeAttrs.

  misc.nix still contains a lot of stuff that should be refactored and
  moved to other files.

svn path=/nixpkgs/trunk/; revision=14013
Diffstat (limited to 'pkgs/lib/lists.nix')
-rw-r--r--pkgs/lib/lists.nix118
1 files changed, 118 insertions, 0 deletions
diff --git a/pkgs/lib/lists.nix b/pkgs/lib/lists.nix
new file mode 100644
index 00000000000..b186e97a55b
--- /dev/null
+++ b/pkgs/lib/lists.nix
@@ -0,0 +1,118 @@
+# General list operations.
+
+rec {
+  inherit (builtins) head tail isList;
+
+
+  # "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 = op: nul: list:
+    if list == []
+    then nul
+    else op (head list) (fold op nul (tail list));
+
+    
+  # Left fold: `fold op nul [x_1 x_2 ... x_n] == op (... (op (op nul
+  # x_1) x_2) ... x_n)'.
+  foldl = op: nul: list:
+    if list == []
+    then nul
+    else foldl op (op nul (head list)) (tail list);
+
+
+  # Concatenate a list of lists.
+  concatLists = fold (x: y: x ++ y) [];
+
+
+  # Map and concatenate the result.
+  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.  E.g., `flatten [1 [2 [3] 4] 5]
+  # == [1 2 3 4 5]' and `flatten 1 == [1]'.
+  flatten = x:
+    if isList x
+    then fold (x: y: (flatten x) ++ y) [] x
+    else [x];
+
+    
+  # Filter a list using a predicate; that is, return a list containing
+  # every element from `list' for which `pred' returns true.
+  filter = pred: list:
+    fold (x: y: if pred x then [x] ++ y else y) [] list;
+
+
+  # Return true if `list' has an element `x':
+  elem = x: list: fold (a: bs: x == a || bs) false list;
+
+
+  # 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.
+  findSingle = pred: default: multiple: list:
+    let found = filter pred list;
+    in if found == [] then default
+       else if tail found != [] then multiple
+       else head found;
+
+
+  # Return true iff function `pred' returns true for at least element
+  # of `list'.
+  any = pred: list:
+    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
+  # `list'.
+  all = pred: list:
+    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.
+  eqLists = xs: ys:
+    if xs == [] && ys == [] then true
+    else if xs == [] || ys == [] then false
+    else head xs == head ys && eqLists (tail xs) (tail ys);
+
+    
+  # 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').
+  optional = cond: elem: if cond then [elem] else [];
+
+
+  # Return a list or an empty list, dependening on a boolean value.
+  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.
+  toList = x: if builtins.isList x then x else [x];
+
+    
+  # Return a list of integers from `first' up to and including `last'.
+  range = first: last:
+    if builtins.lessThan last first
+    then []
+    else [first] ++ range (builtins.add first 1) last;
+
+    
+  # Partition the elements of a list in two lists, `right' and
+  # `wrong', depending on the evaluation of a predicate.
+  partition = pred:
+    fold (h: t:
+      if pred h
+      then { right = [h] ++ t.right; wrong = t.wrong; }
+      else { right = t.right; wrong = [h] ++ t.wrong; }
+    ) { right = []; wrong = []; };
+
+    
+}