|
|
|
@ -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"; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|