| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | # General list operations. | 
					
						
							| 
									
										
										
										
											2013-10-24 02:02:04 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | with import ./trivial.nix; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  | rec { | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  |   inherit (builtins) head tail length isList elemAt concatLists filter elem genList; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /*  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" ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-06-08 22:42:42 +00:00
										 |  |  |  |   singleton = x: [x]; | 
					
						
							| 
									
										
										
										
											2012-08-14 13:42:43 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* "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). | 
					
						
							| 
									
										
										
										
											2009-06-08 22:42:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        concat = fold (a: b: a + b) "z" | 
					
						
							|  |  |  |  |        concat [ "a" "b" "c" ] | 
					
						
							| 
									
										
										
										
											2016-05-26 11:52:35 +01:00
										 |  |  |  |        => "abcz" | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |   fold = op: nul: list: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       len = length list; | 
					
						
							|  |  |  |  |       fold' = n: | 
					
						
							|  |  |  |  |         if n == len | 
					
						
							| 
									
										
										
										
											2012-08-13 14:19:50 -04:00
										 |  |  |  |         then nul | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |         else op (elemAt list n) (fold' (n + 1)); | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |     in fold' 0; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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" | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |   foldl = op: nul: list: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       len = length list; | 
					
						
							|  |  |  |  |       foldl' = n: | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |         if n == -1 | 
					
						
							| 
									
										
										
										
											2012-08-13 14:19:50 -04:00
										 |  |  |  |         then nul | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |         else op (foldl' (n - 1)) (elemAt list n); | 
					
						
							|  |  |  |  |     in foldl' (length list - 1); | 
					
						
							| 
									
										
										
										
											2012-08-13 14:19:50 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Strict version of foldl.
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      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.) | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |  |   foldl' = builtins.foldl' or foldl; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Map with index
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      FIXME(zimbatm): why does this start to count at 1? | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        imap (i: v: "${v}-${toString i}") ["a" "b"] | 
					
						
							|  |  |  |  |        => [ "a-1" "b-2" ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   imap = f: list: genList (n: f (n + 1) (elemAt list n)) (length list); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Map and concatenate the result.
 | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        concatMap (x: [x] ++ ["z"]) ["a" "b"] | 
					
						
							|  |  |  |  |        => [ "a" "z" "b" "z" ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   concatMap = f: list: concatLists (map f list); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Flatten the argument into a single list; that is, nested lists are
 | 
					
						
							|  |  |  |  |      spliced into the top-level lists. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        flatten [1 [2 [3] 4] 5] | 
					
						
							|  |  |  |  |        => [1 2 3 4 5] | 
					
						
							|  |  |  |  |        flatten 1 | 
					
						
							|  |  |  |  |        => [1] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   flatten = x: | 
					
						
							|  |  |  |  |     if isList x | 
					
						
							| 
									
										
										
										
											2016-08-10 12:02:58 +02:00
										 |  |  |  |     then concatMap (y: flatten y) x | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |     else [x]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Remove elements equal to 'e' from a list.  Useful for buildInputs.
 | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        remove 3 [ 1 3 4 3 ] | 
					
						
							|  |  |  |  |        => [ 1 4 ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2011-03-15 09:24:47 +00:00
										 |  |  |  |   remove = e: filter (x: x != e); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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" | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   findSingle = pred: default: multiple: list: | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |     let found = filter pred list; len = length found; | 
					
						
							|  |  |  |  |     in if len == 0 then default | 
					
						
							|  |  |  |  |       else if len != 1 then multiple | 
					
						
							|  |  |  |  |       else head found; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Find the first element in the list matching the specified
 | 
					
						
							|  |  |  |  |      predicate or returns `default' if no such element exists. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        findFirst (x: x > 3) 7 [ 1 6 4 ] | 
					
						
							|  |  |  |  |        => 6 | 
					
						
							|  |  |  |  |        findFirst (x: x > 9) 7 [ 1 6 4 ] | 
					
						
							|  |  |  |  |        => 7 | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-07-22 14:43:39 +00:00
										 |  |  |  |   findFirst = pred: default: list: | 
					
						
							|  |  |  |  |     let found = filter pred list; | 
					
						
							|  |  |  |  |     in if found == [] then default else head found; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return true iff function `pred' returns true for at least element
 | 
					
						
							|  |  |  |  |      of `list'. | 
					
						
							| 
									
										
										
										
											2009-07-22 14:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        any isString [ 1 "a" { } ] | 
					
						
							|  |  |  |  |        => true | 
					
						
							|  |  |  |  |        any isString [ 1 { } ] | 
					
						
							|  |  |  |  |        => false | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-23 19:25:58 +02:00
										 |  |  |  |   any = builtins.any or (pred: fold (x: y: if pred x then true else y) false); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return true iff function `pred' returns true for all elements of
 | 
					
						
							|  |  |  |  |      `list'. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        all (x: x < 3) [ 1 2 ] | 
					
						
							|  |  |  |  |        => true | 
					
						
							|  |  |  |  |        all (x: x < 3) [ 1 2 3 ] | 
					
						
							|  |  |  |  |        => false | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-23 19:25:58 +02:00
										 |  |  |  |   all = builtins.all or (pred: fold (x: y: if pred x then y else false) true); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Count how many times function `pred' returns true for the elements
 | 
					
						
							|  |  |  |  |      of `list'. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        count (x: x == 3) [ 3 2 3 4 6 ] | 
					
						
							|  |  |  |  |        => 2 | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |  |   count = pred: foldl' (c: x: if pred x then c + 1 else c) 0; | 
					
						
							| 
									
										
										
										
											2013-10-28 04:46:36 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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'). | 
					
						
							| 
									
										
										
										
											2013-10-28 04:46:36 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        optional true "foo" | 
					
						
							|  |  |  |  |        => [ "foo" ] | 
					
						
							|  |  |  |  |        optional false "foo" | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   optional = cond: elem: if cond then [elem] else []; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return a list or an empty list, dependening on a boolean value.
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        optionals true [ 2 3 ] | 
					
						
							|  |  |  |  |        => [ 2 3 ] | 
					
						
							|  |  |  |  |        optionals false [ 2 3 ] | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   optionals = cond: elems: if cond then elems else []; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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 "] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |   toList = x: if isList x then x else [x]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return a list of integers from `first' up to and including `last'.
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        range 2 4 | 
					
						
							|  |  |  |  |        => [ 2 3 4 ] | 
					
						
							|  |  |  |  |        range 3 2 | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   range = first: last: | 
					
						
							|  |  |  |  |     if first > last then | 
					
						
							|  |  |  |  |       [] | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  |     else | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |       genList (n: first + n) (last - first + 1); | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Splits the elements of a list in two lists, `right' and
 | 
					
						
							|  |  |  |  |      `wrong', depending on the evaluation of a predicate. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        partition (x: x > 2) [ 5 1 2 3 4 ] | 
					
						
							|  |  |  |  |        => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; } | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-08-29 17:25:33 +02:00
										 |  |  |  |   partition = builtins.partition or (pred: | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |     fold (h: t: | 
					
						
							|  |  |  |  |       if pred h | 
					
						
							|  |  |  |  |       then { right = [h] ++ t.right; wrong = t.wrong; } | 
					
						
							|  |  |  |  |       else { right = t.right; wrong = [h] ++ t.wrong; } | 
					
						
							| 
									
										
										
										
											2016-08-29 17:25:33 +02:00
										 |  |  |  |     ) { right = []; wrong = []; }); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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. | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] | 
					
						
							|  |  |  |  |        => ["he" "lo"] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   zipListsWith = f: fst: snd: | 
					
						
							|  |  |  |  |     genList | 
					
						
							|  |  |  |  |       (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd)); | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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"; } ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:14 +00:00
										 |  |  |  |   zipLists = zipListsWith (fst: snd: { inherit fst snd; }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Reverse the order of the elements of a list.
 | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |        reverseList [ "b" "o" "j" ] | 
					
						
							|  |  |  |  |        => [ "j" "o" "b" ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   reverseList = xs: | 
					
						
							|  |  |  |  |     let l = length xs; in genList (n: elemAt xs (l - n - 1)) l; | 
					
						
							| 
									
										
										
										
											2009-11-07 01:59:55 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-25 19:07:19 +00:00
										 |  |  |  |   /* Depth-First Search (DFS) for lists `list != []`.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      `before a b == true` means that `b` depends on `a` (there's an | 
					
						
							|  |  |  |  |      edge from `b` to `a`). | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      Examples: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ] | 
					
						
							|  |  |  |  |            == { minimal = "/";                  # minimal element | 
					
						
							|  |  |  |  |                 visited = [ "/home/user" ];     # seen elements (in reverse order) | 
					
						
							|  |  |  |  |                 rest    = [ "/home" "other" ];  # everything else | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ] | 
					
						
							|  |  |  |  |            == { cycle   = "/";                  # cycle encountered at this element | 
					
						
							|  |  |  |  |                 loops   = [ "/" ];              # and continues to these elements | 
					
						
							|  |  |  |  |                 visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order) | 
					
						
							|  |  |  |  |                 rest    = [ "/home" "other" ];  # everything else | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   listDfs = stopOnCycles: before: list: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       dfs' = us: visited: rest: | 
					
						
							|  |  |  |  |         let | 
					
						
							|  |  |  |  |           c = filter (x: before x us) visited; | 
					
						
							|  |  |  |  |           b = partition (x: before x us) rest; | 
					
						
							|  |  |  |  |         in if stopOnCycles && (length c > 0) | 
					
						
							|  |  |  |  |            then { cycle = us; loops = c; inherit visited rest; } | 
					
						
							|  |  |  |  |            else if length b.right == 0 | 
					
						
							|  |  |  |  |                 then # nothing is before us | 
					
						
							|  |  |  |  |                      { minimal = us; inherit visited rest; } | 
					
						
							|  |  |  |  |                 else # grab the first one before us and continue | 
					
						
							|  |  |  |  |                      dfs' (head b.right) | 
					
						
							|  |  |  |  |                           ([ us ] ++ visited) | 
					
						
							|  |  |  |  |                           (tail b.right ++ b.wrong); | 
					
						
							|  |  |  |  |     in dfs' (head list) [] (tail list); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Sort a list based on a partial ordering using DFS. This
 | 
					
						
							|  |  |  |  |      implementation is O(N^2), if your ordering is linear, use `sort` | 
					
						
							|  |  |  |  |      instead. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      `before a b == true` means that `b` should be after `a` | 
					
						
							|  |  |  |  |      in the result. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      Examples: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          toposort hasPrefix [ "/home/user" "other" "/" "/home" ] | 
					
						
							|  |  |  |  |            == { result = [ "/" "/home" "/home/user" "other" ]; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ] | 
					
						
							|  |  |  |  |            == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle | 
					
						
							|  |  |  |  |                 loops = [ "/" ]; }                # loops back to these elements | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          toposort hasPrefix [ "other" "/home/user" "/home" "/" ] | 
					
						
							|  |  |  |  |            == { result = [ "other" "/" "/home" "/home/user" ]; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |          toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   toposort = before: list: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       dfsthis = listDfs true before list; | 
					
						
							|  |  |  |  |       toporest = toposort before (dfsthis.visited ++ dfsthis.rest); | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |       if length list < 2 | 
					
						
							|  |  |  |  |       then # finish | 
					
						
							|  |  |  |  |            { result =  list; } | 
					
						
							|  |  |  |  |       else if dfsthis ? "cycle" | 
					
						
							|  |  |  |  |            then # there's a cycle, starting from the current vertex, return it | 
					
						
							|  |  |  |  |                 { cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited); | 
					
						
							|  |  |  |  |                   inherit (dfsthis) loops; } | 
					
						
							|  |  |  |  |            else if toporest ? "cycle" | 
					
						
							|  |  |  |  |                 then # there's a cycle somewhere else in the graph, return it | 
					
						
							|  |  |  |  |                      toporest | 
					
						
							|  |  |  |  |                 # Slow, but short. Can be made a bit faster with an explicit stack. | 
					
						
							|  |  |  |  |                 else # there are no cycles | 
					
						
							|  |  |  |  |                      { result = [ dfsthis.minimal ] ++ toporest.result; }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* 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. | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        sort (a: b: a < b) [ 5 3 7 ] | 
					
						
							|  |  |  |  |        => [ 3 5 7 ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-28 18:42:04 +02:00
										 |  |  |  |   sort = builtins.sort or ( | 
					
						
							|  |  |  |  |     strictLess: list: | 
					
						
							| 
									
										
										
										
											2009-11-07 01:59:55 +00:00
										 |  |  |  |     let | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |       len = length list; | 
					
						
							|  |  |  |  |       first = head list; | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |       pivot' = n: acc@{ left, right }: let el = elemAt list n; next = pivot' (n + 1); in | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |  |         if n == len | 
					
						
							|  |  |  |  |           then acc | 
					
						
							|  |  |  |  |         else if strictLess first el | 
					
						
							|  |  |  |  |           then next { inherit left; right = [ el ] ++ right; } | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |           next { left = [ el ] ++ left; inherit right; }; | 
					
						
							|  |  |  |  |       pivot = pivot' 1 { left = []; right = []; }; | 
					
						
							| 
									
										
										
										
											2009-11-07 01:59:55 +00:00
										 |  |  |  |     in | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |       if len < 2 then list | 
					
						
							| 
									
										
										
										
											2015-07-28 18:42:04 +02:00
										 |  |  |  |       else (sort strictLess pivot.left) ++  [ first ] ++  (sort strictLess pivot.right)); | 
					
						
							| 
									
										
										
										
											2009-11-07 01:59:55 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return the first (at most) N elements of a list.
 | 
					
						
							| 
									
										
										
										
											2009-12-08 21:47:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        take 2 [ "a" "b" "c" "d" ] | 
					
						
							|  |  |  |  |        => [ "a" "b" ] | 
					
						
							|  |  |  |  |        take 2 [ ] | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   take = count: sublist 0 count; | 
					
						
							| 
									
										
										
										
											2009-12-08 21:47:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Remove the first (at most) N elements of a list.
 | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        drop 2 [ "a" "b" "c" "d" ] | 
					
						
							|  |  |  |  |        => [ "c" "d" ] | 
					
						
							|  |  |  |  |        drop 2 [ ] | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |  |   drop = count: list: sublist count (length list) list; | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return a list consisting of at most ‘count’ elements of ‘list’,
 | 
					
						
							|  |  |  |  |      starting at index ‘start’. | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        sublist 1 3 [ "a" "b" "c" "d" "e" ] | 
					
						
							|  |  |  |  |        => [ "b" "c" "d" ] | 
					
						
							|  |  |  |  |        sublist 1 3 [ ] | 
					
						
							|  |  |  |  |        => [ ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  |   sublist = start: count: list: | 
					
						
							|  |  |  |  |     let len = length list; in | 
					
						
							|  |  |  |  |     genList | 
					
						
							|  |  |  |  |       (n: elemAt list (n + start)) | 
					
						
							|  |  |  |  |       (if start >= len then 0 | 
					
						
							|  |  |  |  |        else if start + count > len then len - start | 
					
						
							|  |  |  |  |        else count); | 
					
						
							| 
									
										
										
										
											2010-04-17 18:26:40 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return the last element of a list.
 | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        last [ 1 2 3 ] | 
					
						
							|  |  |  |  |        => 3 | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2010-01-03 11:05:42 +00:00
										 |  |  |  |   last = list: | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |     assert list != []; elemAt list (length list - 1); | 
					
						
							| 
									
										
										
										
											2010-01-03 11:05:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Return all elements but the last
 | 
					
						
							| 
									
										
										
										
											2012-08-13 18:26:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        init [ 1 2 3 ] | 
					
						
							|  |  |  |  |        => [ 1 2 ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2014-09-16 18:03:46 +02:00
										 |  |  |  |   init = list: assert list != []; take (length list - 1) list; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* FIXME(zimbatm) Not used anywhere
 | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2013-12-12 14:01:48 -05:00
										 |  |  |  |   crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [f]; | 
					
						
							| 
									
										
										
										
											2014-04-09 00:02:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Remove duplicate elements from the list. O(n^2) complexity.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |      Example: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |        unique [ 3 2 3 4 ] | 
					
						
							|  |  |  |  |        => [ 3 2 4 ] | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2014-11-12 21:36:26 +01:00
										 |  |  |  |   unique = list: | 
					
						
							|  |  |  |  |     if list == [] then | 
					
						
							|  |  |  |  |       [] | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       let | 
					
						
							|  |  |  |  |         x = head list; | 
					
						
							|  |  |  |  |         xs = unique (drop 1 list); | 
					
						
							|  |  |  |  |       in [x] ++ remove x xs; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Intersects list 'e' and another list. O(nm) complexity.
 | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        intersectLists [ 1 2 3 ] [ 6 3 2 ] | 
					
						
							|  |  |  |  |        => [ 3 2 ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-03-21 17:09:38 +01:00
										 |  |  |  |   intersectLists = e: filter (x: elem x e); | 
					
						
							| 
									
										
										
										
											2015-02-28 04:02:15 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |   /* Subtracts list 'e' from another list. O(nm) complexity.
 | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |  |      Example: | 
					
						
							|  |  |  |  |        subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ] | 
					
						
							|  |  |  |  |        => [ 1 4 5 ] | 
					
						
							|  |  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-03-21 17:09:38 +01:00
										 |  |  |  |   subtractLists = e: filter (x: !(elem x e)); | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | } |