| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | # General list operations. | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  | { lib }: | 
					
						
							| 
									
										
										
										
											2018-04-08 10:55:06 +00:00
										 |  |  | let | 
					
						
							|  |  |  |   inherit (lib.strings) toInt; | 
					
						
							| 
									
										
										
										
											2020-10-20 13:47:24 +02:00
										 |  |  |   inherit (lib.trivial) compare min; | 
					
						
							| 
									
										
										
										
											2018-04-08 10:55:06 +00:00
										 |  |  | in | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  | rec { | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-29 14:06:47 +01:00
										 |  |  |   inherit (builtins) head tail length isList elemAt concatLists filter elem genList map; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /*  Create a list consisting of a single element.  `singleton x` is
 | 
					
						
							|  |  |  |       sometimes more convenient with respect to indentation than `[x]` | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |       when x spans multiple lines. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |       Type: singleton :: a -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |       Example: | 
					
						
							|  |  |  |         singleton "foo" | 
					
						
							|  |  |  |         => [ "foo" ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2009-06-08 22:42:42 +00:00
										 |  |  |   singleton = x: [x]; | 
					
						
							| 
									
										
										
										
											2012-08-14 13:42:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-14 13:17:49 +03:00
										 |  |  |   /*  Apply the function to each element in the list. Same as `map`, but arguments
 | 
					
						
							|  |  |  |       flipped. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 14:06:20 +03:00
										 |  |  |       Type: forEach :: [a] -> (a -> b) -> [b] | 
					
						
							| 
									
										
										
										
											2019-07-14 13:17:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       Example: | 
					
						
							| 
									
										
										
										
											2019-08-05 14:06:20 +03:00
										 |  |  |         forEach [ 1 2 ] (x: | 
					
						
							| 
									
										
										
										
											2019-07-14 13:17:49 +03:00
										 |  |  |           toString x | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         => [ "1" "2" ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2019-08-05 14:06:20 +03:00
										 |  |  |   forEach = xs: f: map f xs; | 
					
						
							| 
									
										
										
										
											2019-07-14 13:17:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* “right fold” a binary function `op` between successive elements of
 | 
					
						
							|  |  |  |      `list` with `nul' as the starting value, i.e., | 
					
						
							|  |  |  |      `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: foldr :: (a -> b -> b) -> b -> [a] -> b | 
					
						
							| 
									
										
										
										
											2009-06-08 22:42:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |        concat = foldr (a: b: a + b) "z" | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |        concat [ "a" "b" "c" ] | 
					
						
							| 
									
										
										
										
											2016-05-26 11:52:35 +01:00
										 |  |  |        => "abcz" | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |        # different types | 
					
						
							|  |  |  |        strange = foldr (int: str: toString (int + 1) + str) "a" | 
					
						
							|  |  |  |        strange [ 1 2 3 4 ] | 
					
						
							|  |  |  |        => "2345a" | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |   foldr = op: nul: list: | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* `fold` is an alias of `foldr` for historic reasons */ | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |   # FIXME(Profpatsch): deprecate? | 
					
						
							|  |  |  |   fold = foldr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* “left fold”, like `foldr`, but from the left:
 | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |      `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: foldl :: (b -> a -> b) -> b -> [a] -> b | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        lconcat = foldl (a: b: a + b) "z" | 
					
						
							|  |  |  |        lconcat [ "a" "b" "c" ] | 
					
						
							|  |  |  |        => "zabc" | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |        # different types | 
					
						
							| 
									
										
										
										
											2020-05-07 09:04:02 -04:00
										 |  |  |        lstrange = foldl (str: int: str + toString (int + 1)) "a" | 
					
						
							|  |  |  |        lstrange [ 1 2 3 4 ] | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |        => "a2345" | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-07-12 12:36:36 -04:00
										 |  |  |   foldl = op: nul: list: | 
					
						
							|  |  |  |     let | 
					
						
							|  |  |  |       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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02: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 | 
					
						
							| 
									
										
										
										
											2019-09-06 20:02:36 +02:00
										 |  |  |      with small whole results (in contrast with lazily-generated list or large | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      lists where only a part is consumed.) | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |      Type: foldl' :: (b -> a -> b) -> b -> [a] -> b | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |   foldl' = builtins.foldl' or foldl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-04 23:29:23 +01:00
										 |  |  |   /* Map with index starting from 0
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: imap0 :: (int -> a -> b) -> [a] -> [b] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-04 23:29:23 +01:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        imap0 (i: v: "${v}-${toString i}") ["a" "b"] | 
					
						
							|  |  |  |        => [ "a-0" "b-1" ] | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   imap0 = f: list: genList (n: f n (elemAt list n)) (length list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Map with index starting from 1
 | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: imap1 :: (int -> a -> b) -> [a] -> [b] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							| 
									
										
										
										
											2017-07-04 23:29:23 +01:00
										 |  |  |        imap1 (i: v: "${v}-${toString i}") ["a" "b"] | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |        => [ "a-1" "b-2" ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2017-07-04 23:29:23 +01:00
										 |  |  |   imap1 = 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: concatMap :: (a -> [b]) -> [a] -> [b] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        concatMap (x: [x] ++ ["z"]) ["a" "b"] | 
					
						
							|  |  |  |        => [ "a" "z" "b" "z" ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-07-05 03:01:13 +00:00
										 |  |  |   concatMap = builtins.concatMap or (f: list: concatLists (map f list)); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: remove :: a -> [a] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        remove 3 [ 1 3 4 3 ] | 
					
						
							|  |  |  |        => [ 1 4 ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   remove = | 
					
						
							|  |  |  |     # Element to remove from the list | 
					
						
							|  |  |  |     e: filter (x: x != e); | 
					
						
							| 
									
										
										
										
											2011-03-15 09:24:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |   /* Find the sole element in the list matching the specified
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      predicate, returns `default` if no such element exists, or | 
					
						
							|  |  |  |      `multiple` if there are multiple matching elements. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: findSingle :: (a -> bool) -> a -> a -> [a] -> a | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |      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" | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   findSingle = | 
					
						
							|  |  |  |     # Predicate | 
					
						
							|  |  |  |     pred: | 
					
						
							|  |  |  |     # Default value to return if element was not found. | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     # Default value to return if more than one element was found | 
					
						
							|  |  |  |     multiple: | 
					
						
							|  |  |  |     # Input list | 
					
						
							|  |  |  |     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
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      predicate or return `default` if no such element exists. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: findFirst :: (a -> bool) -> a -> [a] -> a | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   findFirst = | 
					
						
							|  |  |  |     # Predicate | 
					
						
							|  |  |  |     pred: | 
					
						
							|  |  |  |     # Default value to return | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     # Input list | 
					
						
							|  |  |  |     list: | 
					
						
							| 
									
										
										
										
											2009-07-22 14:43:39 +00:00
										 |  |  |     let found = filter pred list; | 
					
						
							|  |  |  |     in if found == [] then default else head found; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Return true if function `pred` returns true for at least one
 | 
					
						
							|  |  |  |      element of `list`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: any :: (a -> bool) -> [a] -> bool | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |   any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Return true if function `pred` returns true for all elements of
 | 
					
						
							|  |  |  |      `list`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: all :: (a -> bool) -> [a] -> bool | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |   all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Count how many elements of `list` match the supplied predicate
 | 
					
						
							|  |  |  |      function. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: count :: (a -> bool) -> [a] -> int | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   count = | 
					
						
							|  |  |  |     # Predicate | 
					
						
							|  |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: optional :: bool -> a -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-19 14:41:28 -05:00
										 |  |  |   /* Return a list or an empty list, depending on a boolean value.
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: optionals :: bool -> [a] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        optionals true [ 2 3 ] | 
					
						
							|  |  |  |        => [ 2 3 ] | 
					
						
							|  |  |  |        optionals false [ 2 3 ] | 
					
						
							|  |  |  |        => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   optionals = | 
					
						
							|  |  |  |     # Condition | 
					
						
							|  |  |  |     cond: | 
					
						
							|  |  |  |     # List to return if condition is true | 
					
						
							|  |  |  |     elems: if cond then elems else []; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: range :: int -> int -> [int] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        range 2 4 | 
					
						
							|  |  |  |        => [ 2 3 4 ] | 
					
						
							|  |  |  |        range 3 2 | 
					
						
							|  |  |  |        => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   range = | 
					
						
							|  |  |  |     # First integer in the range | 
					
						
							|  |  |  |     first: | 
					
						
							|  |  |  |     # Last integer in the range | 
					
						
							|  |  |  |     last: | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Splits the elements of a list in two lists, `right` and
 | 
					
						
							|  |  |  |      `wrong`, depending on the evaluation of a predicate. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: (a -> bool) -> [a] -> { right :: [a], wrong :: [a] } | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2017-03-15 19:05:01 +01:00
										 |  |  |     foldr (h: t: | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |       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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-10 17:31:09 +00:00
										 |  |  |   /* Splits the elements of a list into many lists, using the return value of a predicate.
 | 
					
						
							|  |  |  |      Predicate should return a string which becomes keys of attrset `groupBy' returns. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      `groupBy'` allows to customise the combining function and initial value | 
					
						
							| 
									
										
										
										
											2018-06-10 17:31:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] | 
					
						
							|  |  |  |        => { true = [ 5 3 4 ]; false = [ 1 2 ]; } | 
					
						
							|  |  |  |        groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";} | 
					
						
							|  |  |  |                              {name = "xfce";  script = "xfce4-session &";} | 
					
						
							|  |  |  |                              {name = "icewm"; script = "icewmbg &";} | 
					
						
							|  |  |  |                              {name = "mate";  script = "gnome-session &";} | 
					
						
							|  |  |  |                            ] | 
					
						
							|  |  |  |        => { icewm = [ { name = "icewm"; script = "icewm &"; } | 
					
						
							|  |  |  |                       { name = "icewm"; script = "icewmbg &"; } ]; | 
					
						
							|  |  |  |             mate  = [ { name = "mate";  script = "gnome-session &"; } ]; | 
					
						
							|  |  |  |             xfce  = [ { name = "xfce";  script = "xfce4-session &"; } ]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] | 
					
						
							|  |  |  |        => { true = 12; false = 3; } | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   groupBy' = op: nul: pred: lst: | 
					
						
							|  |  |  |     foldl' (r: e: | 
					
						
							|  |  |  |               let | 
					
						
							|  |  |  |                 key = pred e; | 
					
						
							|  |  |  |               in | 
					
						
							|  |  |  |                 r // { ${key} = op (r.${key} or nul) e; } | 
					
						
							|  |  |  |            ) {} lst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   groupBy = groupBy' (sum: e: sum ++ [e]) []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] | 
					
						
							|  |  |  |        => ["he" "lo"] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   zipListsWith = | 
					
						
							|  |  |  |     # Function to zip elements of both lists | 
					
						
							|  |  |  |     f: | 
					
						
							|  |  |  |     # First list | 
					
						
							|  |  |  |     fst: | 
					
						
							|  |  |  |     # Second list | 
					
						
							|  |  |  |     snd: | 
					
						
							| 
									
										
										
										
											2016-06-17 11:06:48 +01:00
										 |  |  |     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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: zipLists :: [a] -> [b] -> [{ fst :: a, snd :: b}] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: reverseList :: [a] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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`). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Example: | 
					
						
							| 
									
										
										
										
											2015-11-25 19:07:19 +00:00
										 |  |  |          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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Example: | 
					
						
							| 
									
										
										
										
											2015-11-25 19:07:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |          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; } | 
					
						
							| 
									
										
										
										
											2019-08-13 21:52:01 +00:00
										 |  |  |       else if dfsthis ? cycle | 
					
						
							| 
									
										
										
										
											2015-11-25 19:07:19 +00:00
										 |  |  |            then # there's a cycle, starting from the current vertex, return it | 
					
						
							|  |  |  |                 { cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited); | 
					
						
							|  |  |  |                   inherit (dfsthis) loops; } | 
					
						
							| 
									
										
										
										
											2019-08-13 21:52:01 +00:00
										 |  |  |            else if toporest ? cycle | 
					
						
							| 
									
										
										
										
											2015-11-25 19:07:19 +00:00
										 |  |  |                 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 21:26:30 +00:00
										 |  |  |   /* Compare two lists element-by-element.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        compareLists compare [] [] | 
					
						
							|  |  |  |        => 0 | 
					
						
							|  |  |  |        compareLists compare [] [ "a" ] | 
					
						
							|  |  |  |        => -1 | 
					
						
							|  |  |  |        compareLists compare [ "a" ] [] | 
					
						
							|  |  |  |        => 1 | 
					
						
							|  |  |  |        compareLists compare [ "a" "b" ] [ "a" "c" ] | 
					
						
							|  |  |  |        => 1 | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   compareLists = cmp: a: b: | 
					
						
							|  |  |  |     if a == [] | 
					
						
							|  |  |  |     then if b == [] | 
					
						
							|  |  |  |          then 0 | 
					
						
							|  |  |  |          else -1 | 
					
						
							|  |  |  |     else if b == [] | 
					
						
							|  |  |  |          then 1 | 
					
						
							|  |  |  |          else let rel = cmp (head a) (head b); in | 
					
						
							|  |  |  |               if rel == 0 | 
					
						
							|  |  |  |               then compareLists cmp (tail a) (tail b) | 
					
						
							|  |  |  |               else rel; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-08 10:55:06 +00:00
										 |  |  |   /* Sort list using "Natural sorting".
 | 
					
						
							|  |  |  |      Numeric portions of strings are sorted in numeric order. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        naturalSort ["disk11" "disk8" "disk100" "disk9"] | 
					
						
							|  |  |  |        => ["disk8" "disk9" "disk11" "disk100"] | 
					
						
							| 
									
										
										
										
											2018-04-08 13:54:39 +00:00
										 |  |  |        naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"] | 
					
						
							|  |  |  |        => ["10.5.16.62" "10.46.133.149" "10.54.16.25"] | 
					
						
							| 
									
										
										
										
											2018-04-08 10:55:06 +00:00
										 |  |  |        naturalSort ["v0.2" "v0.15" "v0.0.9"] | 
					
						
							|  |  |  |        => [ "v0.0.9" "v0.2" "v0.15" ] | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   naturalSort = lst: | 
					
						
							|  |  |  |     let | 
					
						
							|  |  |  |       vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s); | 
					
						
							|  |  |  |       prepared = map (x: [ (vectorise x) x ]) lst; # remember vectorised version for O(n) regex splits | 
					
						
							|  |  |  |       less = a: b: (compareLists compare (head a) (head b)) < 0; | 
					
						
							|  |  |  |     in | 
					
						
							|  |  |  |       map (x: elemAt x 1) (sort less prepared); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: take :: int -> [a] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        take 2 [ "a" "b" "c" "d" ] | 
					
						
							|  |  |  |        => [ "a" "b" ] | 
					
						
							|  |  |  |        take 2 [ ] | 
					
						
							|  |  |  |        => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   take = | 
					
						
							|  |  |  |     # Number of elements to 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: drop :: int -> [a] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        drop 2 [ "a" "b" "c" "d" ] | 
					
						
							|  |  |  |        => [ "c" "d" ] | 
					
						
							|  |  |  |        drop 2 [ ] | 
					
						
							|  |  |  |        => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   drop = | 
					
						
							|  |  |  |     # Number of elements to drop | 
					
						
							|  |  |  |     count: | 
					
						
							|  |  |  |     # Input list | 
					
						
							|  |  |  |     list: sublist count (length list) list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Return a list consisting of at most `count` elements of `list`,
 | 
					
						
							|  |  |  |      starting at index `start`. | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: sublist :: int -> int -> [a] -> [a] | 
					
						
							| 
									
										
										
										
											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 [ ] | 
					
						
							|  |  |  |        => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   sublist = | 
					
						
							|  |  |  |     # Index at which to start the sublist | 
					
						
							|  |  |  |     start: | 
					
						
							|  |  |  |     # Number of elements to take | 
					
						
							|  |  |  |     count: | 
					
						
							|  |  |  |     # Input list | 
					
						
							|  |  |  |     list: | 
					
						
							| 
									
										
										
										
											2015-07-28 17:31:43 +02:00
										 |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      This function throws an error if the list is empty. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: last :: [a] -> a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        last [ 1 2 3 ] | 
					
						
							|  |  |  |        => 3 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2010-01-03 11:05:42 +00:00
										 |  |  |   last = list: | 
					
						
							| 
									
										
										
										
											2018-08-08 19:26:52 +02:00
										 |  |  |     assert lib.assertMsg (list != []) "lists.last: list must not be empty!"; | 
					
						
							| 
									
										
										
										
											2018-08-06 01:36:09 +02:00
										 |  |  |     elemAt list (length list - 1); | 
					
						
							| 
									
										
										
										
											2010-01-03 11:05:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Return all elements but the last.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      This function throws an error if the list is empty. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: init :: [a] -> [a] | 
					
						
							| 
									
										
										
										
											2012-08-13 18:26:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        init [ 1 2 3 ] | 
					
						
							|  |  |  |        => [ 1 2 ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-08-06 01:36:09 +02:00
										 |  |  |   init = list: | 
					
						
							| 
									
										
										
										
											2018-08-08 19:26:52 +02:00
										 |  |  |     assert lib.assertMsg (list != []) "lists.init: list must not be empty!"; | 
					
						
							| 
									
										
										
										
											2018-08-06 01:36:09 +02:00
										 |  |  |     take (length list - 1) list; | 
					
						
							| 
									
										
										
										
											2014-09-16 18:03:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |   /* Return the image of the cross product of some lists by a function.
 | 
					
						
							| 
									
										
										
										
											2018-02-09 18:40:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Example: | 
					
						
							|  |  |  |       crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]] | 
					
						
							|  |  |  |       => [ "13" "14" "23" "24" ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Type: unique :: [a] -> [a] | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-27 19:23:06 +02:00
										 |  |  |      Example: | 
					
						
							| 
									
										
										
										
											2016-02-28 23:27:06 +00:00
										 |  |  |        unique [ 3 2 3 4 ] | 
					
						
							|  |  |  |        => [ 3 2 4 ] | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-11-24 06:20:01 +01:00
										 |  |  |  unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) []; | 
					
						
							| 
									
										
										
										
											2014-11-12 21:36:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-02 09:32:43 +02:00
										 |  |  |   /* Test if two lists have no common element.
 | 
					
						
							|  |  |  |      It should be slightly more efficient than (intersectLists a b == []) | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   mutuallyExclusive = a: b: | 
					
						
							|  |  |  |     (builtins.length a) == 0 || | 
					
						
							|  |  |  |     (!(builtins.elem (builtins.head a) b) && | 
					
						
							|  |  |  |      mutuallyExclusive (builtins.tail a) b); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | } |