Merge pull request #311434 from lucasew/20240513-xrdp-and-friends
[NixPkgs.git] / lib / lists.nix
blobca436d7a9c94b5806d13c763a526eb212f715ac8
1 /**
2   General list operations.
3 */
4 { lib }:
5 let
6   inherit (lib.strings) toInt;
7   inherit (lib.trivial) compare min id warn pipe;
8   inherit (lib.attrsets) mapAttrs;
9 in
10 rec {
12   inherit (builtins) head tail length isList elemAt concatLists filter elem genList map;
14   /**
15     Create a list consisting of a single element. `singleton x` is
16     sometimes more convenient with respect to indentation than `[x]`
17     when x spans multiple lines.
19     # Inputs
21     `x`
23     : 1\. Function argument
25     # Type
27     ```
28     singleton :: a -> [a]
29     ```
31     # Examples
32     :::{.example}
33     ## `lib.lists.singleton` usage example
35     ```nix
36     singleton "foo"
37     => [ "foo" ]
38     ```
40     :::
41   */
42   singleton = x: [x];
44   /**
45     Apply the function to each element in the list.
46     Same as `map`, but arguments flipped.
48     # Inputs
50     `xs`
52     : 1\. Function argument
54     `f`
56     : 2\. Function argument
58     # Type
60     ```
61     forEach :: [a] -> (a -> b) -> [b]
62     ```
64     # Examples
65     :::{.example}
66     ## `lib.lists.forEach` usage example
68     ```nix
69     forEach [ 1 2 ] (x:
70       toString x
71     )
72     => [ "1" "2" ]
73     ```
75     :::
76   */
77   forEach = xs: f: map f xs;
79   /**
80     “right fold” a binary function `op` between successive elements of
81     `list` with `nul` as the starting value, i.e.,
82     `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
85     # Inputs
87     `op`
89     : 1\. Function argument
91     `nul`
93     : 2\. Function argument
95     `list`
97     : 3\. Function argument
99     # Type
101     ```
102     foldr :: (a -> b -> b) -> b -> [a] -> b
103     ```
105     # Examples
106     :::{.example}
107     ## `lib.lists.foldr` usage example
109     ```nix
110     concat = foldr (a: b: a + b) "z"
111     concat [ "a" "b" "c" ]
112     => "abcz"
113     # different types
114     strange = foldr (int: str: toString (int + 1) + str) "a"
115     strange [ 1 2 3 4 ]
116     => "2345a"
117     ```
119     :::
120   */
121   foldr = op: nul: list:
122     let
123       len = length list;
124       fold' = n:
125         if n == len
126         then nul
127         else op (elemAt list n) (fold' (n + 1));
128     in fold' 0;
130   /**
131     `fold` is an alias of `foldr` for historic reasons
132   */
133   # FIXME(Profpatsch): deprecate?
134   fold = foldr;
137   /**
138     “left fold”, like `foldr`, but from the left:
140     `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
142     # Inputs
144     `op`
146     : 1\. Function argument
148     `nul`
150     : 2\. Function argument
152     `list`
154     : 3\. Function argument
156     # Type
158     ```
159     foldl :: (b -> a -> b) -> b -> [a] -> b
160     ```
162     # Examples
163     :::{.example}
164     ## `lib.lists.foldl` usage example
166     ```nix
167     lconcat = foldl (a: b: a + b) "z"
168     lconcat [ "a" "b" "c" ]
169     => "zabc"
170     # different types
171     lstrange = foldl (str: int: str + toString (int + 1)) "a"
172     lstrange [ 1 2 3 4 ]
173     => "a2345"
174     ```
176     :::
177   */
178   foldl = op: nul: list:
179     let
180       foldl' = n:
181         if n == -1
182         then nul
183         else op (foldl' (n - 1)) (elemAt list n);
184     in foldl' (length list - 1);
186   /**
187     Reduce a list by applying a binary operator from left to right,
188     starting with an initial accumulator.
190     Before each application of the operator, the accumulator value is evaluated.
191     This behavior makes this function stricter than [`foldl`](#function-library-lib.lists.foldl).
193     Unlike [`builtins.foldl'`](https://nixos.org/manual/nix/unstable/language/builtins.html#builtins-foldl'),
194     the initial accumulator argument is evaluated before the first iteration.
196     A call like
198     ```nix
199     foldl' op acc₀ [ x₀ x₁ x₂ ... xₙ₋₁ xₙ ]
200     ```
202     is (denotationally) equivalent to the following,
203     but with the added benefit that `foldl'` itself will never overflow the stack.
205     ```nix
206     let
207       acc₁   = builtins.seq acc₀   (op acc₀   x₀  );
208       acc₂   = builtins.seq acc₁   (op acc₁   x₁  );
209       acc₃   = builtins.seq acc₂   (op acc₂   x₂  );
210       ...
211       accₙ   = builtins.seq accₙ₋₁ (op accₙ₋₁ xₙ₋₁);
212       accₙ₊₁ = builtins.seq accₙ   (op accₙ   xₙ  );
213     in
214     accₙ₊₁
216     # Or ignoring builtins.seq
217     op (op (... (op (op (op acc₀ x₀) x₁) x₂) ...) xₙ₋₁) xₙ
218     ```
220     # Inputs
222     `op`
224     : The binary operation to run, where the two arguments are:
226     1. `acc`: The current accumulator value: Either the initial one for the first iteration, or the result of the previous iteration
227     2. `x`: The corresponding list element for this iteration
229     `acc`
231     : The initial accumulator value.
233       The accumulator value is evaluated in any case before the first iteration starts.
235       To avoid evaluation even before the `list` argument is given an eta expansion can be used:
237       ```nix
238       list: lib.foldl' op acc list
239       ```
241     `list`
243     : The list to fold
245     # Type
247     ```
248     foldl' :: (acc -> x -> acc) -> acc -> [x] -> acc
249     ```
251     # Examples
252     :::{.example}
253     ## `lib.lists.foldl'` usage example
255     ```nix
256     foldl' (acc: x: acc + x) 0 [1 2 3]
257     => 6
258     ```
260     :::
261   */
262   foldl' =
263     op:
264     acc:
265     # The builtin `foldl'` is a bit lazier than one might expect.
266     # See https://github.com/NixOS/nix/pull/7158.
267     # In particular, the initial accumulator value is not forced before the first iteration starts.
268     builtins.seq acc
269       (builtins.foldl' op acc);
271   /**
272     Map with index starting from 0
274     # Inputs
276     `f`
278     : 1\. Function argument
280     `list`
282     : 2\. Function argument
284     # Type
286     ```
287     imap0 :: (int -> a -> b) -> [a] -> [b]
288     ```
290     # Examples
291     :::{.example}
292     ## `lib.lists.imap0` usage example
294     ```nix
295     imap0 (i: v: "${v}-${toString i}") ["a" "b"]
296     => [ "a-0" "b-1" ]
297     ```
299     :::
300   */
301   imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
303   /**
304     Map with index starting from 1
307     # Inputs
309     `f`
311     : 1\. Function argument
313     `list`
315     : 2\. Function argument
317     # Type
319     ```
320     imap1 :: (int -> a -> b) -> [a] -> [b]
321     ```
323     # Examples
324     :::{.example}
325     ## `lib.lists.imap1` usage example
327     ```nix
328     imap1 (i: v: "${v}-${toString i}") ["a" "b"]
329     => [ "a-1" "b-2" ]
330     ```
332     :::
333   */
334   imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
336   /**
337     Filter a list for elements that satisfy a predicate function.
338     The predicate function is called with both the index and value for each element.
339     It must return `true`/`false` to include/exclude a given element in the result.
340     This function is strict in the result of the predicate function for each element.
341     This function has O(n) complexity.
343     Also see [`builtins.filter`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filter) (available as `lib.lists.filter`),
344     which can be used instead when the index isn't needed.
346     # Inputs
348     `ipred`
350     : The predicate function, it takes two arguments:
351       - 1. (int): the index of the element.
352       - 2. (a): the value of the element.
354       It must return `true`/`false` to include/exclude a given element from the result.
356     `list`
358     : The list to filter using the predicate.
360     # Type
361     ```
362     ifilter0 :: (int -> a -> bool) -> [a] -> [a]
363     ```
365     # Examples
366     :::{.example}
367     ## `lib.lists.ifilter0` usage example
369     ```nix
370     ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ]
371     => [ 1 3 ]
372     ```
373     :::
374   */
375   ifilter0 =
376     ipred:
377     input:
378     map (idx: elemAt input idx) (
379       filter (idx: ipred idx (elemAt input idx)) (
380         genList (x: x) (length input)
381       )
382     );
384   /**
385     Map and concatenate the result.
387     # Type
389     ```
390     concatMap :: (a -> [b]) -> [a] -> [b]
391     ```
393     # Examples
394     :::{.example}
395     ## `lib.lists.concatMap` usage example
397     ```nix
398     concatMap (x: [x] ++ ["z"]) ["a" "b"]
399     => [ "a" "z" "b" "z" ]
400     ```
402     :::
403   */
404   concatMap = builtins.concatMap;
406   /**
407     Flatten the argument into a single list; that is, nested lists are
408     spliced into the top-level lists.
411     # Inputs
413     `x`
415     : 1\. Function argument
418     # Examples
419     :::{.example}
420     ## `lib.lists.flatten` usage example
422     ```nix
423     flatten [1 [2 [3] 4] 5]
424     => [1 2 3 4 5]
425     flatten 1
426     => [1]
427     ```
429     :::
430   */
431   flatten = x:
432     if isList x
433     then concatMap (y: flatten y) x
434     else [x];
436   /**
437     Remove elements equal to 'e' from a list.  Useful for buildInputs.
440     # Inputs
442     `e`
444     : Element to remove from `list`
446     `list`
448     : The list
450     # Type
452     ```
453     remove :: a -> [a] -> [a]
454     ```
456     # Examples
457     :::{.example}
458     ## `lib.lists.remove` usage example
460     ```nix
461     remove 3 [ 1 3 4 3 ]
462     => [ 1 4 ]
463     ```
465     :::
466   */
467   remove =
468     e: filter (x: x != e);
470   /**
471     Find the sole element in the list matching the specified
472     predicate.
474     Returns `default` if no such element exists, or
475     `multiple` if there are multiple matching elements.
478     # Inputs
480     `pred`
482     : Predicate
484     `default`
486     : Default value to return if element was not found.
488     `multiple`
490     : Default value to return if more than one element was found
492     `list`
494     : Input list
496     # Type
498     ```
499     findSingle :: (a -> bool) -> a -> a -> [a] -> a
500     ```
502     # Examples
503     :::{.example}
504     ## `lib.lists.findSingle` usage example
506     ```nix
507     findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
508     => "multiple"
509     findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
510     => 3
511     findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
512     => "none"
513     ```
515     :::
516   */
517   findSingle =
518     pred:
519     default:
520     multiple:
521     list:
522     let found = filter pred list; len = length found;
523     in if len == 0 then default
524       else if len != 1 then multiple
525       else head found;
527   /**
528     Find the first index in the list matching the specified
529     predicate or return `default` if no such element exists.
531     # Inputs
533     `pred`
535     : Predicate
537     `default`
539     : Default value to return
541     `list`
543     : Input list
545     # Type
547     ```
548     findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b)
549     ```
551     # Examples
552     :::{.example}
553     ## `lib.lists.findFirstIndex` usage example
555     ```nix
556     findFirstIndex (x: x > 3) null [ 0 6 4 ]
557     => 1
558     findFirstIndex (x: x > 9) null [ 0 6 4 ]
559     => null
560     ```
562     :::
563   */
564   findFirstIndex =
565     pred:
566     default:
567     list:
568     let
569       # A naive recursive implementation would be much simpler, but
570       # would also overflow the evaluator stack. We use `foldl'` as a workaround
571       # because it reuses the same stack space, evaluating the function for one
572       # element after another. We can't return early, so this means that we
573       # sacrifice early cutoff, but that appears to be an acceptable cost. A
574       # clever scheme with "exponential search" is possible, but appears over-
575       # engineered for now. See https://github.com/NixOS/nixpkgs/pull/235267
577       # Invariant:
578       # - if index < 0 then el == elemAt list (- index - 1) and all elements before el didn't satisfy pred
579       # - if index >= 0 then pred (elemAt list index) and all elements before (elemAt list index) didn't satisfy pred
580       #
581       # We start with index -1 and the 0'th element of the list, which satisfies the invariant
582       resultIndex = foldl' (index: el:
583         if index < 0 then
584           # No match yet before the current index, we need to check the element
585           if pred el then
586             # We have a match! Turn it into the actual index to prevent future iterations from modifying it
587             - index - 1
588           else
589             # Still no match, update the index to the next element (we're counting down, so minus one)
590             index - 1
591         else
592           # There's already a match, propagate the index without evaluating anything
593           index
594       ) (-1) list;
595     in
596     if resultIndex < 0 then
597       default
598     else
599       resultIndex;
601   /**
602     Find the first element in the list matching the specified
603     predicate or return `default` if no such element exists.
605     # Inputs
607     `pred`
609     : Predicate
611     `default`
613     : Default value to return
615     `list`
617     : Input list
619     # Type
621     ```
622     findFirst :: (a -> bool) -> a -> [a] -> a
623     ```
625     # Examples
626     :::{.example}
627     ## `lib.lists.findFirst` usage example
629     ```nix
630     findFirst (x: x > 3) 7 [ 1 6 4 ]
631     => 6
632     findFirst (x: x > 9) 7 [ 1 6 4 ]
633     => 7
634     ```
636     :::
637   */
638   findFirst =
639     pred:
640     default:
641     list:
642     let
643       index = findFirstIndex pred null list;
644     in
645     if index == null then
646       default
647     else
648       elemAt list index;
650   /**
651     Return true if function `pred` returns true for at least one
652     element of `list`.
654     # Inputs
656     `pred`
658     : Predicate
660     `list`
662     : Input list
664     # Type
666     ```
667     any :: (a -> bool) -> [a] -> bool
668     ```
670     # Examples
671     :::{.example}
672     ## `lib.lists.any` usage example
674     ```nix
675     any isString [ 1 "a" { } ]
676     => true
677     any isString [ 1 { } ]
678     => false
679     ```
681     :::
682   */
683   any = builtins.any;
685   /**
686     Return true if function `pred` returns true for all elements of
687     `list`.
689     # Inputs
691     `pred`
693     : Predicate
695     `list`
697     : Input list
699     # Type
701     ```
702     all :: (a -> bool) -> [a] -> bool
703     ```
705     # Examples
706     :::{.example}
707     ## `lib.lists.all` usage example
709     ```nix
710     all (x: x < 3) [ 1 2 ]
711     => true
712     all (x: x < 3) [ 1 2 3 ]
713     => false
714     ```
716     :::
717   */
718   all = builtins.all;
720   /**
721     Count how many elements of `list` match the supplied predicate
722     function.
724     # Inputs
726     `pred`
728     : Predicate
730     # Type
732     ```
733     count :: (a -> bool) -> [a] -> int
734     ```
736     # Examples
737     :::{.example}
738     ## `lib.lists.count` usage example
740     ```nix
741     count (x: x == 3) [ 3 2 3 4 6 ]
742     => 2
743     ```
745     :::
746   */
747   count =
748     pred: foldl' (c: x: if pred x then c + 1 else c) 0;
750   /**
751     Return a singleton list or an empty list, depending on a boolean
752     value.  Useful when building lists with optional elements
753     (e.g. `++ optional (system == "i686-linux") firefox`).
755     # Inputs
757     `cond`
759     : 1\. Function argument
761     `elem`
763     : 2\. Function argument
765     # Type
767     ```
768     optional :: bool -> a -> [a]
769     ```
771     # Examples
772     :::{.example}
773     ## `lib.lists.optional` usage example
775     ```nix
776     optional true "foo"
777     => [ "foo" ]
778     optional false "foo"
779     => [ ]
780     ```
782     :::
783   */
784   optional = cond: elem: if cond then [elem] else [];
786   /**
787     Return a list or an empty list, depending on a boolean value.
789     # Inputs
791     `cond`
793     : Condition
795     `elems`
797     : List to return if condition is true
799     # Type
801     ```
802     optionals :: bool -> [a] -> [a]
803     ```
805     # Examples
806     :::{.example}
807     ## `lib.lists.optionals` usage example
809     ```nix
810     optionals true [ 2 3 ]
811     => [ 2 3 ]
812     optionals false [ 2 3 ]
813     => [ ]
814     ```
816     :::
817   */
818   optionals =
819     cond:
820     elems: if cond then elems else [];
823   /**
824     If argument is a list, return it; else, wrap it in a singleton
825     list. If you're using this, you should almost certainly
826     reconsider if there isn't a more "well-typed" approach.
828     # Inputs
830     `x`
832     : 1\. Function argument
834     # Examples
835     :::{.example}
836     ## `lib.lists.toList` usage example
838     ```nix
839     toList [ 1 2 ]
840     => [ 1 2 ]
841     toList "hi"
842     => [ "hi "]
843     ```
845     :::
846   */
847   toList = x: if isList x then x else [x];
849   /**
850     Return a list of integers from `first` up to and including `last`.
852     # Inputs
854     `first`
856     : First integer in the range
858     `last`
860     : Last integer in the range
862     # Type
864     ```
865     range :: int -> int -> [int]
866     ```
868     # Examples
869     :::{.example}
870     ## `lib.lists.range` usage example
872     ```nix
873     range 2 4
874     => [ 2 3 4 ]
875     range 3 2
876     => [ ]
877     ```
879     :::
880   */
881   range =
882     first:
883     last:
884     if first > last then
885       []
886     else
887       genList (n: first + n) (last - first + 1);
889   /**
890     Return a list with `n` copies of an element.
892     # Inputs
894     `n`
896     : 1\. Function argument
898     `elem`
900     : 2\. Function argument
902     # Type
904     ```
905     replicate :: int -> a -> [a]
906     ```
908     # Examples
909     :::{.example}
910     ## `lib.lists.replicate` usage example
912     ```nix
913     replicate 3 "a"
914     => [ "a" "a" "a" ]
915     replicate 2 true
916     => [ true true ]
917     ```
919     :::
920   */
921   replicate = n: elem: genList (_: elem) n;
923   /**
924     Splits the elements of a list in two lists, `right` and
925     `wrong`, depending on the evaluation of a predicate.
927     # Inputs
929     `pred`
931     : Predicate
933     `list`
935     : Input list
937     # Type
939     ```
940     (a -> bool) -> [a] -> { right :: [a]; wrong :: [a]; }
941     ```
943     # Examples
944     :::{.example}
945     ## `lib.lists.partition` usage example
947     ```nix
948     partition (x: x > 2) [ 5 1 2 3 4 ]
949     => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
950     ```
952     :::
953   */
954   partition = builtins.partition;
956   /**
957     Splits the elements of a list into many lists, using the return value of a predicate.
958     Predicate should return a string which becomes keys of attrset `groupBy` returns.
959     `groupBy'` allows to customise the combining function and initial value
961     # Inputs
963     `op`
965     : 1\. Function argument
967     `nul`
969     : 2\. Function argument
971     `pred`
973     : 3\. Function argument
975     `lst`
977     : 4\. Function argument
980     # Examples
981     :::{.example}
982     ## `lib.lists.groupBy'` usage example
984     ```nix
985     groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
986     => { true = [ 5 3 4 ]; false = [ 1 2 ]; }
987     groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";}
988                           {name = "xfce";  script = "xfce4-session &";}
989                           {name = "icewm"; script = "icewmbg &";}
990                           {name = "mate";  script = "gnome-session &";}
991                         ]
992     => { icewm = [ { name = "icewm"; script = "icewm &"; }
993                    { name = "icewm"; script = "icewmbg &"; } ];
994          mate  = [ { name = "mate";  script = "gnome-session &"; } ];
995          xfce  = [ { name = "xfce";  script = "xfce4-session &"; } ];
996        }
998     groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
999     => { true = 12; false = 3; }
1000     ```
1002     :::
1003   */
1004   groupBy' = op: nul: pred: lst: mapAttrs (name: foldl op nul) (groupBy pred lst);
1006   groupBy = builtins.groupBy or (
1007     pred: foldl' (r: e:
1008        let
1009          key = pred e;
1010        in
1011          r // { ${key} = (r.${key} or []) ++ [e]; }
1012     ) {});
1014   /**
1015     Merges two lists of the same size together. If the sizes aren't the same
1016     the merging stops at the shortest. How both lists are merged is defined
1017     by the first argument.
1019     # Inputs
1021     `f`
1023     : Function to zip elements of both lists
1025     `fst`
1027     : First list
1029     `snd`
1031     : Second list
1033     # Type
1035     ```
1036     zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
1037     ```
1039     # Examples
1040     :::{.example}
1041     ## `lib.lists.zipListsWith` usage example
1043     ```nix
1044     zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
1045     => ["he" "lo"]
1046     ```
1048     :::
1049   */
1050   zipListsWith =
1051     f:
1052     fst:
1053     snd:
1054     genList
1055       (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
1057   /**
1058     Merges two lists of the same size together. If the sizes aren't the same
1059     the merging stops at the shortest.
1061     # Inputs
1063     `fst`
1065     : First list
1067     `snd`
1069     : Second list
1071     # Type
1073     ```
1074     zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }]
1075     ```
1077     # Examples
1078     :::{.example}
1079     ## `lib.lists.zipLists` usage example
1081     ```nix
1082     zipLists [ 1 2 ] [ "a" "b" ]
1083     => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
1084     ```
1086     :::
1087   */
1088   zipLists = zipListsWith (fst: snd: { inherit fst snd; });
1090   /**
1091     Reverse the order of the elements of a list.
1093     # Inputs
1095     `xs`
1097     : 1\. Function argument
1099     # Type
1101     ```
1102     reverseList :: [a] -> [a]
1103     ```
1105     # Examples
1106     :::{.example}
1107     ## `lib.lists.reverseList` usage example
1109     ```nix
1110     reverseList [ "b" "o" "j" ]
1111     => [ "j" "o" "b" ]
1112     ```
1114     :::
1115   */
1116   reverseList = xs:
1117     let l = length xs; in genList (n: elemAt xs (l - n - 1)) l;
1119   /**
1120     Depth-First Search (DFS) for lists `list != []`.
1122     `before a b == true` means that `b` depends on `a` (there's an
1123     edge from `b` to `a`).
1126     # Inputs
1128     `stopOnCycles`
1130     : 1\. Function argument
1132     `before`
1134     : 2\. Function argument
1136     `list`
1138     : 3\. Function argument
1141     # Examples
1142     :::{.example}
1143     ## `lib.lists.listDfs` usage example
1145     ```nix
1146     listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
1147       == { minimal = "/";                  # minimal element
1148            visited = [ "/home/user" ];     # seen elements (in reverse order)
1149            rest    = [ "/home" "other" ];  # everything else
1150          }
1152     listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1153       == { cycle   = "/";                  # cycle encountered at this element
1154            loops   = [ "/" ];              # and continues to these elements
1155            visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order)
1156            rest    = [ "/home" "other" ];  # everything else
1157     ```
1159     :::
1160   */
1161   listDfs = stopOnCycles: before: list:
1162     let
1163       dfs' = us: visited: rest:
1164         let
1165           c = filter (x: before x us) visited;
1166           b = partition (x: before x us) rest;
1167         in if stopOnCycles && (length c > 0)
1168            then { cycle = us; loops = c; inherit visited rest; }
1169            else if length b.right == 0
1170                 then # nothing is before us
1171                      { minimal = us; inherit visited rest; }
1172                 else # grab the first one before us and continue
1173                      dfs' (head b.right)
1174                           ([ us ] ++ visited)
1175                           (tail b.right ++ b.wrong);
1176     in dfs' (head list) [] (tail list);
1178   /**
1179     Sort a list based on a partial ordering using DFS. This
1180     implementation is O(N^2), if your ordering is linear, use `sort`
1181     instead.
1183     `before a b == true` means that `b` should be after `a`
1184     in the result.
1187     # Inputs
1189     `before`
1191     : 1\. Function argument
1193     `list`
1195     : 2\. Function argument
1198     # Examples
1199     :::{.example}
1200     ## `lib.lists.toposort` usage example
1202     ```nix
1203     toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
1204       == { result = [ "/" "/home" "/home/user" "other" ]; }
1206     toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1207       == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle
1208            loops = [ "/" ]; }                # loops back to these elements
1210     toposort hasPrefix [ "other" "/home/user" "/home" "/" ]
1211       == { result = [ "other" "/" "/home" "/home/user" ]; }
1213     toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
1214     ```
1216     :::
1217   */
1218   toposort = before: list:
1219     let
1220       dfsthis = listDfs true before list;
1221       toporest = toposort before (dfsthis.visited ++ dfsthis.rest);
1222     in
1223       if length list < 2
1224       then # finish
1225            { result =  list; }
1226       else if dfsthis ? cycle
1227            then # there's a cycle, starting from the current vertex, return it
1228                 { cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited);
1229                   inherit (dfsthis) loops; }
1230            else if toporest ? cycle
1231                 then # there's a cycle somewhere else in the graph, return it
1232                      toporest
1233                 # Slow, but short. Can be made a bit faster with an explicit stack.
1234                 else # there are no cycles
1235                      { result = [ dfsthis.minimal ] ++ toporest.result; };
1237   /**
1238     Sort a list based on a comparator function which compares two
1239     elements and returns true if the first argument is strictly below
1240     the second argument.  The returned list is sorted in an increasing
1241     order.  The implementation does a quick-sort.
1243     See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the
1244     default comparison on a function-derived property, and may be more efficient.
1246     # Inputs
1248     `comparator`
1250     : 1\. Function argument
1252     `list`
1254     : 2\. Function argument
1256     # Type
1258     ```
1259     sort :: (a -> a -> Bool) -> [a] -> [a]
1260     ```
1262     # Examples
1263     :::{.example}
1264     ## `lib.lists.sort` usage example
1266     ```nix
1267     sort (p: q: p < q) [ 5 3 7 ]
1268     => [ 3 5 7 ]
1269     ```
1271     :::
1272   */
1273   sort = builtins.sort;
1275   /**
1276     Sort a list based on the default comparison of a derived property `b`.
1278     The items are returned in `b`-increasing order.
1280     **Performance**:
1282     The passed function `f` is only evaluated once per item,
1283     unlike an unprepared [`sort`](#function-library-lib.lists.sort) using
1284     `f p < f q`.
1286     **Laws**:
1287     ```nix
1288     sortOn f == sort (p: q: f p < f q)
1289     ```
1292     # Inputs
1294     `f`
1296     : 1\. Function argument
1298     `list`
1300     : 2\. Function argument
1302     # Type
1304     ```
1305     sortOn :: (a -> b) -> [a] -> [a], for comparable b
1306     ```
1308     # Examples
1309     :::{.example}
1310     ## `lib.lists.sortOn` usage example
1312     ```nix
1313     sortOn stringLength [ "aa" "b" "cccc" ]
1314     => [ "b" "aa" "cccc" ]
1315     ```
1317     :::
1318   */
1319   sortOn = f: list:
1320     let
1321       # Heterogenous list as pair may be ugly, but requires minimal allocations.
1322       pairs = map (x: [(f x) x]) list;
1323     in
1324       map
1325         (x: builtins.elemAt x 1)
1326         (sort
1327           # Compare the first element of the pairs
1328           # Do not factor out the `<`, to avoid calls in hot code; duplicate instead.
1329           (a: b: head a < head b)
1330           pairs);
1332   /**
1333     Compare two lists element-by-element.
1335     # Inputs
1337     `cmp`
1339     : 1\. Function argument
1341     `a`
1343     : 2\. Function argument
1345     `b`
1347     : 3\. Function argument
1350     # Examples
1351     :::{.example}
1352     ## `lib.lists.compareLists` usage example
1354     ```nix
1355     compareLists compare [] []
1356     => 0
1357     compareLists compare [] [ "a" ]
1358     => -1
1359     compareLists compare [ "a" ] []
1360     => 1
1361     compareLists compare [ "a" "b" ] [ "a" "c" ]
1362     => -1
1363     ```
1365     :::
1366   */
1367   compareLists = cmp: a: b:
1368     if a == []
1369     then if b == []
1370          then 0
1371          else -1
1372     else if b == []
1373          then 1
1374          else let rel = cmp (head a) (head b); in
1375               if rel == 0
1376               then compareLists cmp (tail a) (tail b)
1377               else rel;
1379   /**
1380     Sort list using "Natural sorting".
1381     Numeric portions of strings are sorted in numeric order.
1384     # Inputs
1386     `lst`
1388     : 1\. Function argument
1391     # Examples
1392     :::{.example}
1393     ## `lib.lists.naturalSort` usage example
1395     ```nix
1396     naturalSort ["disk11" "disk8" "disk100" "disk9"]
1397     => ["disk8" "disk9" "disk11" "disk100"]
1398     naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
1399     => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
1400     naturalSort ["v0.2" "v0.15" "v0.0.9"]
1401     => [ "v0.0.9" "v0.2" "v0.15" ]
1402     ```
1404     :::
1405   */
1406   naturalSort = lst:
1407     let
1408       vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
1409       prepared = map (x: [ (vectorise x) x ]) lst; # remember vectorised version for O(n) regex splits
1410       less = a: b: (compareLists compare (head a) (head b)) < 0;
1411     in
1412       map (x: elemAt x 1) (sort less prepared);
1414   /**
1415     Return the first (at most) N elements of a list.
1418     # Inputs
1420     `count`
1422     : Number of elements to take
1424     `list`
1426     : Input list
1428     # Type
1430     ```
1431     take :: int -> [a] -> [a]
1432     ```
1434     # Examples
1435     :::{.example}
1436     ## `lib.lists.take` usage example
1438     ```nix
1439     take 2 [ "a" "b" "c" "d" ]
1440     => [ "a" "b" ]
1441     take 2 [ ]
1442     => [ ]
1443     ```
1445     :::
1446   */
1447   take =
1448     count: sublist 0 count;
1450   /**
1451     Remove the first (at most) N elements of a list.
1454     # Inputs
1456     `count`
1458     : Number of elements to drop
1460     `list`
1462     : Input list
1464     # Type
1466     ```
1467     drop :: int -> [a] -> [a]
1468     ```
1470     # Examples
1471     :::{.example}
1472     ## `lib.lists.drop` usage example
1474     ```nix
1475     drop 2 [ "a" "b" "c" "d" ]
1476     => [ "c" "d" ]
1477     drop 2 [ ]
1478     => [ ]
1479     ```
1481     :::
1482   */
1483   drop =
1484     count:
1485     list: sublist count (length list) list;
1487   /**
1488     Whether the first list is a prefix of the second list.
1491     # Inputs
1493     `list1`
1495     : 1\. Function argument
1497     `list2`
1499     : 2\. Function argument
1501     # Type
1503     ```
1504     hasPrefix :: [a] -> [a] -> bool
1505     ```
1507     # Examples
1508     :::{.example}
1509     ## `lib.lists.hasPrefix` usage example
1511     ```nix
1512     hasPrefix [ 1 2 ] [ 1 2 3 4 ]
1513     => true
1514     hasPrefix [ 0 1 ] [ 1 2 3 4 ]
1515     => false
1516     ```
1518     :::
1519   */
1520   hasPrefix =
1521     list1:
1522     list2:
1523     take (length list1) list2 == list1;
1525   /**
1526     Remove the first list as a prefix from the second list.
1527     Error if the first list isn't a prefix of the second list.
1529     # Inputs
1531     `list1`
1533     : 1\. Function argument
1535     `list2`
1537     : 2\. Function argument
1539     # Type
1541     ```
1542     removePrefix :: [a] -> [a] -> [a]
1543     ```
1545     # Examples
1546     :::{.example}
1547     ## `lib.lists.removePrefix` usage example
1549     ```nix
1550     removePrefix [ 1 2 ] [ 1 2 3 4 ]
1551     => [ 3 4 ]
1552     removePrefix [ 0 1 ] [ 1 2 3 4 ]
1553     => <error>
1554     ```
1556     :::
1557   */
1558   removePrefix =
1559     list1:
1560     list2:
1561     if hasPrefix list1 list2 then
1562       drop (length list1) list2
1563     else
1564       throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument";
1566   /**
1567     Return a list consisting of at most `count` elements of `list`,
1568     starting at index `start`.
1570     # Inputs
1572     `start`
1574     : Index at which to start the sublist
1576     `count`
1578     : Number of elements to take
1580     `list`
1582     : Input list
1584     # Type
1586     ```
1587     sublist :: int -> int -> [a] -> [a]
1588     ```
1590     # Examples
1591     :::{.example}
1592     ## `lib.lists.sublist` usage example
1594     ```nix
1595     sublist 1 3 [ "a" "b" "c" "d" "e" ]
1596     => [ "b" "c" "d" ]
1597     sublist 1 3 [ ]
1598     => [ ]
1599     ```
1601     :::
1602   */
1603   sublist =
1604     start:
1605     count:
1606     list:
1607     let len = length list; in
1608     genList
1609       (n: elemAt list (n + start))
1610       (if start >= len then 0
1611        else if start + count > len then len - start
1612        else count);
1614   /**
1615     The common prefix of two lists.
1618     # Inputs
1620     `list1`
1622     : 1\. Function argument
1624     `list2`
1626     : 2\. Function argument
1628     # Type
1630     ```
1631     commonPrefix :: [a] -> [a] -> [a]
1632     ```
1634     # Examples
1635     :::{.example}
1636     ## `lib.lists.commonPrefix` usage example
1638     ```nix
1639     commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]
1640     => [ 1 2 ]
1641     commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]
1642     => [ 1 2 3 ]
1643     commonPrefix [ 1 2 3 ] [ 4 5 6 ]
1644     => [ ]
1645     ```
1647     :::
1648   */
1649   commonPrefix =
1650     list1:
1651     list2:
1652     let
1653       # Zip the lists together into a list of booleans whether each element matches
1654       matchings = zipListsWith (fst: snd: fst != snd) list1 list2;
1655       # Find the first index where the elements don't match,
1656       # which will then also be the length of the common prefix.
1657       # If all elements match, we fall back to the length of the zipped list,
1658       # which is the same as the length of the smaller list.
1659       commonPrefixLength = findFirstIndex id (length matchings) matchings;
1660     in
1661     take commonPrefixLength list1;
1663   /**
1664     Return the last element of a list.
1666     This function throws an error if the list is empty.
1669     # Inputs
1671     `list`
1673     : 1\. Function argument
1675     # Type
1677     ```
1678     last :: [a] -> a
1679     ```
1681     # Examples
1682     :::{.example}
1683     ## `lib.lists.last` usage example
1685     ```nix
1686     last [ 1 2 3 ]
1687     => 3
1688     ```
1690     :::
1691   */
1692   last = list:
1693     assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
1694     elemAt list (length list - 1);
1696   /**
1697     Return all elements but the last.
1699     This function throws an error if the list is empty.
1702     # Inputs
1704     `list`
1706     : 1\. Function argument
1708     # Type
1710     ```
1711     init :: [a] -> [a]
1712     ```
1714     # Examples
1715     :::{.example}
1716     ## `lib.lists.init` usage example
1718     ```nix
1719     init [ 1 2 3 ]
1720     => [ 1 2 ]
1721     ```
1723     :::
1724   */
1725   init = list:
1726     assert lib.assertMsg (list != []) "lists.init: list must not be empty!";
1727     take (length list - 1) list;
1730   /**
1731     Return the image of the cross product of some lists by a function.
1734     # Examples
1735     :::{.example}
1736     ## `lib.lists.crossLists` usage example
1738     ```nix
1739     crossLists (x: y: "${toString x}${toString y}") [[1 2] [3 4]]
1740     => [ "13" "14" "23" "24" ]
1741     ```
1743     The following function call is equivalent to the one deprecated above:
1745     ```nix
1746     mapCartesianProduct (x: "${toString x.a}${toString x.b}") { a = [1 2]; b = [3 4]; }
1747     => [ "13" "14" "23" "24" ]
1748     ```
1749     :::
1750   */
1751   crossLists = warn
1752     ''lib.crossLists is deprecated, use lib.mapCartesianProduct instead.
1754     For example, the following function call:
1756     nix-repl> lib.crossLists (x: y: x+y) [[1 2] [3 4]]
1757     [ 4 5 5 6 ]
1759     Can now be replaced by the following one:
1761     nix-repl> lib.mapCartesianProduct ({x,y}: x+y) { x = [1 2]; y = [3 4]; }
1762     [ 4 5 5 6 ]
1763     ''
1764     (f: foldl (fs: args: concatMap (f: map f args) fs) [f]);
1766   /**
1767     Remove duplicate elements from the `list`. O(n^2) complexity.
1770     # Inputs
1772     `list`
1774     : Input list
1776     # Type
1778     ```
1779     unique :: [a] -> [a]
1780     ```
1782     # Examples
1783     :::{.example}
1784     ## `lib.lists.unique` usage example
1786     ```nix
1787     unique [ 3 2 3 4 ]
1788     => [ 3 2 4 ]
1789     ```
1791     :::
1792   */
1793   unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [];
1795   /**
1796     Check if list contains only unique elements. O(n^2) complexity.
1799     # Inputs
1801     `list`
1803     : 1\. Function argument
1805     # Type
1807     ```
1808     allUnique :: [a] -> bool
1809     ```
1811     # Examples
1812     :::{.example}
1813     ## `lib.lists.allUnique` usage example
1815     ```nix
1816     allUnique [ 3 2 3 4 ]
1817     => false
1818     allUnique [ 3 2 4 1 ]
1819     => true
1820     ```
1822     :::
1823   */
1824   allUnique = list: (length (unique list) == length list);
1827   /**
1828     Intersects list 'list1' and another list (`list2`).
1830     O(nm) complexity.
1832     # Inputs
1834     `list1`
1836     : First list
1838     `list2`
1840     : Second list
1843     # Examples
1844     :::{.example}
1845     ## `lib.lists.intersectLists` usage example
1847     ```nix
1848     intersectLists [ 1 2 3 ] [ 6 3 2 ]
1849     => [ 3 2 ]
1850     ```
1852     :::
1853   */
1854   intersectLists = e: filter (x: elem x e);
1856   /**
1857     Subtracts list 'e' from another list (`list2`).
1859     O(nm) complexity.
1861     # Inputs
1863     `e`
1865     : First list
1867     `list2`
1869     : Second list
1872     # Examples
1873     :::{.example}
1874     ## `lib.lists.subtractLists` usage example
1876     ```nix
1877     subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
1878     => [ 1 4 5 ]
1879     ```
1881     :::
1882   */
1883   subtractLists = e: filter (x: !(elem x e));
1885   /**
1886     Test if two lists have no common element.
1887     It should be slightly more efficient than (intersectLists a b == [])
1889     # Inputs
1891     `a`
1893     : 1\. Function argument
1895     `b`
1897     : 2\. Function argument
1898   */
1899   mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b);