···1# General list operations.
02{ lib }:
3with lib.trivial;
4let
···89 inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
1011- /* Create a list consisting of a single element. `singleton x' is
12- sometimes more convenient with respect to indentation than `[x]'
13 when x spans multiple lines.
140015 Example:
16 singleton "foo"
17 => [ "foo" ]
18 */
19 singleton = x: [x];
2021- /* “right fold” a binary function `op' between successive elements of
22- `list' with `nul' as the starting value, i.e.,
23- `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))'.
24- Type:
25- foldr :: (a -> b -> b) -> b -> [a] -> b
2627 Example:
28 concat = foldr (a: b: a + b) "z"
···42 else op (elemAt list n) (fold' (n + 1));
43 in fold' 0;
4445- /* `fold' is an alias of `foldr' for historic reasons */
46 # FIXME(Profpatsch): deprecate?
47 fold = foldr;
484950- /* “left fold”, like `foldr', but from the left:
51 `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
5253- Type:
54- foldl :: (b -> a -> b) -> b -> [a] -> b
5556 Example:
57 lconcat = foldl (a: b: a + b) "z"
···70 else op (foldl' (n - 1)) (elemAt list n);
71 in foldl' (length list - 1);
7273- /* Strict version of `foldl'.
7475 The difference is that evaluation is forced upon access. Usually used
76 with small whole results (in contract with lazily-generated list or large
77 lists where only a part is consumed.)
0078 */
79 foldl' = builtins.foldl' or foldl;
8081 /* Map with index starting from 0
820083 Example:
84 imap0 (i: v: "${v}-${toString i}") ["a" "b"]
85 => [ "a-0" "b-1" ]
···87 imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
8889 /* Map with index starting from 1
009091 Example:
92 imap1 (i: v: "${v}-${toString i}") ["a" "b"]
···95 imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
9697 /* Map and concatenate the result.
009899 Example:
100 concatMap (x: [x] ++ ["z"]) ["a" "b"]
···118119 /* Remove elements equal to 'e' from a list. Useful for buildInputs.
12000121 Example:
122 remove 3 [ 1 3 4 3 ]
123 => [ 1 4 ]
124 */
125- remove = e: filter (x: x != e);
00126127 /* Find the sole element in the list matching the specified
128- predicate, returns `default' if no such element exists, or
129- `multiple' if there are multiple matching elements.
00130131 Example:
132 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
···136 findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
137 => "none"
138 */
139- findSingle = pred: default: multiple: list:
00000000140 let found = filter pred list; len = length found;
141 in if len == 0 then default
142 else if len != 1 then multiple
143 else head found;
144145 /* Find the first element in the list matching the specified
146- predicate or returns `default' if no such element exists.
00147148 Example:
149 findFirst (x: x > 3) 7 [ 1 6 4 ]
···151 findFirst (x: x > 9) 7 [ 1 6 4 ]
152 => 7
153 */
154- findFirst = pred: default: list:
000000155 let found = filter pred list;
156 in if found == [] then default else head found;
157158- /* Return true iff function `pred' returns true for at least element
159- of `list'.
00160161 Example:
162 any isString [ 1 "a" { } ]
···166 */
167 any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false);
168169- /* Return true iff function `pred' returns true for all elements of
170- `list'.
00171172 Example:
173 all (x: x < 3) [ 1 2 ]
···177 */
178 all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true);
179180- /* Count how many times function `pred' returns true for the elements
181- of `list'.
00182183 Example:
184 count (x: x == 3) [ 3 2 3 4 6 ]
185 => 2
186 */
187- count = pred: foldl' (c: x: if pred x then c + 1 else c) 0;
00188189 /* Return a singleton list or an empty list, depending on a boolean
190 value. Useful when building lists with optional elements
191 (e.g. `++ optional (system == "i686-linux") flashplayer').
00192193 Example:
194 optional true "foo"
···200201 /* Return a list or an empty list, depending on a boolean value.
20200203 Example:
204 optionals true [ 2 3 ]
205 => [ 2 3 ]
206 optionals false [ 2 3 ]
207 => [ ]
208 */
209- optionals = cond: elems: if cond then elems else [];
0000210211212 /* If argument is a list, return it; else, wrap it in a singleton
···223224 /* Return a list of integers from `first' up to and including `last'.
22500226 Example:
227 range 2 4
228 => [ 2 3 4 ]
229 range 3 2
230 => [ ]
231 */
232- range = first: last:
0000233 if first > last then
234 []
235 else
236 genList (n: first + n) (last - first + 1);
237238- /* Splits the elements of a list in two lists, `right' and
239- `wrong', depending on the evaluation of a predicate.
00240241 Example:
242 partition (x: x > 2) [ 5 1 2 3 4 ]
···252 /* Splits the elements of a list into many lists, using the return value of a predicate.
253 Predicate should return a string which becomes keys of attrset `groupBy' returns.
254255- `groupBy'' allows to customise the combining function and initial value
256257 Example:
258 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
···268 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
269 }
270271-272- groupBy' allows to customise the combining function and initial value
273-274- Example:
275 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
276 => { true = 12; false = 3; }
277 */
···289 the merging stops at the shortest. How both lists are merged is defined
290 by the first argument.
29100292 Example:
293 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
294 => ["he" "lo"]
295 */
296- zipListsWith = f: fst: snd:
000000297 genList
298 (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
299300 /* Merges two lists of the same size together. If the sizes aren't the same
301 the merging stops at the shortest.
30200303 Example:
304 zipLists [ 1 2 ] [ "a" "b" ]
305 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
···308309 /* Reverse the order of the elements of a list.
31000311 Example:
312313 reverseList [ "b" "o" "j" ]
···321 `before a b == true` means that `b` depends on `a` (there's an
322 edge from `b` to `a`).
323324- Examples:
325-326 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
327 == { minimal = "/"; # minimal element
328 visited = [ "/home/user" ]; # seen elements (in reverse order)
···336 rest = [ "/home" "other" ]; # everything else
337338 */
339-340 listDfs = stopOnCycles: before: list:
341 let
342 dfs' = us: visited: rest:
···361 `before a b == true` means that `b` should be after `a`
362 in the result.
363364- Examples:
365366 toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
367 == { result = [ "/" "/home" "/home/user" "other" ]; }
···376 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
377378 */
379-380 toposort = before: list:
381 let
382 dfsthis = listDfs true before list;
···467468 /* Return the first (at most) N elements of a list.
46900470 Example:
471 take 2 [ "a" "b" "c" "d" ]
472 => [ "a" "b" ]
473 take 2 [ ]
474 => [ ]
475 */
476- take = count: sublist 0 count;
00477478 /* Remove the first (at most) N elements of a list.
00479480 Example:
481 drop 2 [ "a" "b" "c" "d" ]
···483 drop 2 [ ]
484 => [ ]
485 */
486- drop = count: list: sublist count (length list) list;
0000487488- /* Return a list consisting of at most ‘count’ elements of ‘list’,
489- starting at index ‘start’.
00490491 Example:
492 sublist 1 3 [ "a" "b" "c" "d" "e" ]
···494 sublist 1 3 [ ]
495 => [ ]
496 */
497- sublist = start: count: list:
000000498 let len = length list; in
499 genList
500 (n: elemAt list (n + start))
···503 else count);
504505 /* Return the last element of a list.
0000506507 Example:
508 last [ 1 2 3 ]
···512 assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
513 elemAt list (length list - 1);
514515- /* Return all elements but the last
0000516517 Example:
518 init [ 1 2 3 ]
···523 take (length list - 1) list;
524525526- /* return the image of the cross product of some lists by a function
527528 Example:
529 crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]]
···534535 /* Remove duplicate elements from the list. O(n^2) complexity.
53600537 Example:
538-539 unique [ 3 2 3 4 ]
540 => [ 3 2 4 ]
541 */
···1# General list operations.
2+3{ lib }:
4with lib.trivial;
5let
···910 inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
1112+ /* Create a list consisting of a single element. `singleton x` is
13+ sometimes more convenient with respect to indentation than `[x]`
14 when x spans multiple lines.
1516+ Type: singleton :: a -> [a]
17+18 Example:
19 singleton "foo"
20 => [ "foo" ]
21 */
22 singleton = x: [x];
2324+ /* “right fold” a binary function `op` between successive elements of
25+ `list` with `nul' as the starting value, i.e.,
26+ `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
27+28+ Type: foldr :: (a -> b -> b) -> b -> [a] -> b
2930 Example:
31 concat = foldr (a: b: a + b) "z"
···45 else op (elemAt list n) (fold' (n + 1));
46 in fold' 0;
4748+ /* `fold` is an alias of `foldr` for historic reasons */
49 # FIXME(Profpatsch): deprecate?
50 fold = foldr;
515253+ /* “left fold”, like `foldr`, but from the left:
54 `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
5556+ Type: foldl :: (b -> a -> b) -> b -> [a] -> b
05758 Example:
59 lconcat = foldl (a: b: a + b) "z"
···72 else op (foldl' (n - 1)) (elemAt list n);
73 in foldl' (length list - 1);
7475+ /* Strict version of `foldl`.
7677 The difference is that evaluation is forced upon access. Usually used
78 with small whole results (in contract with lazily-generated list or large
79 lists where only a part is consumed.)
80+81+ Type: foldl' :: (b -> a -> b) -> b -> [a] -> b
82 */
83 foldl' = builtins.foldl' or foldl;
8485 /* Map with index starting from 0
8687+ Type: imap0 :: (int -> a -> b) -> [a] -> [b]
88+89 Example:
90 imap0 (i: v: "${v}-${toString i}") ["a" "b"]
91 => [ "a-0" "b-1" ]
···93 imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
9495 /* Map with index starting from 1
96+97+ Type: imap1 :: (int -> a -> b) -> [a] -> [b]
9899 Example:
100 imap1 (i: v: "${v}-${toString i}") ["a" "b"]
···103 imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
104105 /* Map and concatenate the result.
106+107+ Type: concatMap :: (a -> [b]) -> [a] -> [b]
108109 Example:
110 concatMap (x: [x] ++ ["z"]) ["a" "b"]
···128129 /* Remove elements equal to 'e' from a list. Useful for buildInputs.
130131+ Type: remove :: a -> [a] -> [a]
132+133 Example:
134 remove 3 [ 1 3 4 3 ]
135 => [ 1 4 ]
136 */
137+ remove =
138+ # Element to remove from the list
139+ e: filter (x: x != e);
140141 /* Find the sole element in the list matching the specified
142+ predicate, returns `default` if no such element exists, or
143+ `multiple` if there are multiple matching elements.
144+145+ Type: findSingle :: (a -> bool) -> a -> a -> [a] -> a
146147 Example:
148 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
···152 findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
153 => "none"
154 */
155+ findSingle =
156+ # Predicate
157+ pred:
158+ # Default value to return if element was not found.
159+ default:
160+ # Default value to return if more than one element was found
161+ multiple:
162+ # Input list
163+ list:
164 let found = filter pred list; len = length found;
165 in if len == 0 then default
166 else if len != 1 then multiple
167 else head found;
168169 /* Find the first element in the list matching the specified
170+ predicate or return `default` if no such element exists.
171+172+ Type: findFirst :: (a -> bool) -> a -> [a] -> a
173174 Example:
175 findFirst (x: x > 3) 7 [ 1 6 4 ]
···177 findFirst (x: x > 9) 7 [ 1 6 4 ]
178 => 7
179 */
180+ findFirst =
181+ # Predicate
182+ pred:
183+ # Default value to return
184+ default:
185+ # Input list
186+ list:
187 let found = filter pred list;
188 in if found == [] then default else head found;
189190+ /* Return true if function `pred` returns true for at least one
191+ element of `list`.
192+193+ Type: any :: (a -> bool) -> [a] -> bool
194195 Example:
196 any isString [ 1 "a" { } ]
···200 */
201 any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false);
202203+ /* Return true if function `pred` returns true for all elements of
204+ `list`.
205+206+ Type: all :: (a -> bool) -> [a] -> bool
207208 Example:
209 all (x: x < 3) [ 1 2 ]
···213 */
214 all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true);
215216+ /* Count how many elements of `list` match the supplied predicate
217+ function.
218+219+ Type: count :: (a -> bool) -> [a] -> int
220221 Example:
222 count (x: x == 3) [ 3 2 3 4 6 ]
223 => 2
224 */
225+ count =
226+ # Predicate
227+ pred: foldl' (c: x: if pred x then c + 1 else c) 0;
228229 /* Return a singleton list or an empty list, depending on a boolean
230 value. Useful when building lists with optional elements
231 (e.g. `++ optional (system == "i686-linux") flashplayer').
232+233+ Type: optional :: bool -> a -> [a]
234235 Example:
236 optional true "foo"
···242243 /* Return a list or an empty list, depending on a boolean value.
244245+ Type: optionals :: bool -> [a] -> [a]
246+247 Example:
248 optionals true [ 2 3 ]
249 => [ 2 3 ]
250 optionals false [ 2 3 ]
251 => [ ]
252 */
253+ optionals =
254+ # Condition
255+ cond:
256+ # List to return if condition is true
257+ elems: if cond then elems else [];
258259260 /* If argument is a list, return it; else, wrap it in a singleton
···271272 /* Return a list of integers from `first' up to and including `last'.
273274+ Type: range :: int -> int -> [int]
275+276 Example:
277 range 2 4
278 => [ 2 3 4 ]
279 range 3 2
280 => [ ]
281 */
282+ range =
283+ # First integer in the range
284+ first:
285+ # Last integer in the range
286+ last:
287 if first > last then
288 []
289 else
290 genList (n: first + n) (last - first + 1);
291292+ /* Splits the elements of a list in two lists, `right` and
293+ `wrong`, depending on the evaluation of a predicate.
294+295+ Type: (a -> bool) -> [a] -> { right :: [a], wrong :: [a] }
296297 Example:
298 partition (x: x > 2) [ 5 1 2 3 4 ]
···308 /* Splits the elements of a list into many lists, using the return value of a predicate.
309 Predicate should return a string which becomes keys of attrset `groupBy' returns.
310311+ `groupBy'` allows to customise the combining function and initial value
312313 Example:
314 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
···324 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
325 }
3260000327 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
328 => { true = 12; false = 3; }
329 */
···341 the merging stops at the shortest. How both lists are merged is defined
342 by the first argument.
343344+ Type: zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
345+346 Example:
347 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
348 => ["he" "lo"]
349 */
350+ zipListsWith =
351+ # Function to zip elements of both lists
352+ f:
353+ # First list
354+ fst:
355+ # Second list
356+ snd:
357 genList
358 (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
359360 /* Merges two lists of the same size together. If the sizes aren't the same
361 the merging stops at the shortest.
362363+ Type: zipLists :: [a] -> [b] -> [{ fst :: a, snd :: b}]
364+365 Example:
366 zipLists [ 1 2 ] [ "a" "b" ]
367 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
···370371 /* Reverse the order of the elements of a list.
372373+ Type: reverseList :: [a] -> [a]
374+375 Example:
376377 reverseList [ "b" "o" "j" ]
···385 `before a b == true` means that `b` depends on `a` (there's an
386 edge from `b` to `a`).
387388+ Example:
0389 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
390 == { minimal = "/"; # minimal element
391 visited = [ "/home/user" ]; # seen elements (in reverse order)
···399 rest = [ "/home" "other" ]; # everything else
400401 */
0402 listDfs = stopOnCycles: before: list:
403 let
404 dfs' = us: visited: rest:
···423 `before a b == true` means that `b` should be after `a`
424 in the result.
425426+ Example:
427428 toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
429 == { result = [ "/" "/home" "/home/user" "other" ]; }
···438 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
439440 */
0441 toposort = before: list:
442 let
443 dfsthis = listDfs true before list;
···528529 /* Return the first (at most) N elements of a list.
530531+ Type: take :: int -> [a] -> [a]
532+533 Example:
534 take 2 [ "a" "b" "c" "d" ]
535 => [ "a" "b" ]
536 take 2 [ ]
537 => [ ]
538 */
539+ take =
540+ # Number of elements to take
541+ count: sublist 0 count;
542543 /* Remove the first (at most) N elements of a list.
544+545+ Type: drop :: int -> [a] -> [a]
546547 Example:
548 drop 2 [ "a" "b" "c" "d" ]
···550 drop 2 [ ]
551 => [ ]
552 */
553+ drop =
554+ # Number of elements to drop
555+ count:
556+ # Input list
557+ list: sublist count (length list) list;
558559+ /* Return a list consisting of at most `count` elements of `list`,
560+ starting at index `start`.
561+562+ Type: sublist :: int -> int -> [a] -> [a]
563564 Example:
565 sublist 1 3 [ "a" "b" "c" "d" "e" ]
···567 sublist 1 3 [ ]
568 => [ ]
569 */
570+ sublist =
571+ # Index at which to start the sublist
572+ start:
573+ # Number of elements to take
574+ count:
575+ # Input list
576+ list:
577 let len = length list; in
578 genList
579 (n: elemAt list (n + start))
···582 else count);
583584 /* Return the last element of a list.
585+586+ This function throws an error if the list is empty.
587+588+ Type: last :: [a] -> a
589590 Example:
591 last [ 1 2 3 ]
···595 assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
596 elemAt list (length list - 1);
597598+ /* Return all elements but the last.
599+600+ This function throws an error if the list is empty.
601+602+ Type: init :: [a] -> [a]
603604 Example:
605 init [ 1 2 3 ]
···610 take (length list - 1) list;
611612613+ /* Return the image of the cross product of some lists by a function.
614615 Example:
616 crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]]
···621622 /* Remove duplicate elements from the list. O(n^2) complexity.
623624+ Type: unique :: [a] -> [a]
625+626 Example:
0627 unique [ 3 2 3 4 ]
628 => [ 3 2 4 ]
629 */