nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at r-updates 2125 lines 40 kB view raw
1/** 2 General list operations. 3*/ 4{ lib }: 5let 6 inherit (lib.strings) toInt; 7 inherit (lib.trivial) 8 compare 9 min 10 id 11 warn 12 ; 13 inherit (lib.attrsets) mapAttrs attrNames attrValues; 14 inherit (lib) max; 15in 16rec { 17 18 inherit (builtins) 19 head 20 tail 21 length 22 isList 23 elemAt 24 concatLists 25 filter 26 elem 27 genList 28 map 29 ; 30 31 /** 32 Create a list consisting of a single element. `singleton x` is 33 sometimes more convenient with respect to indentation than `[x]` 34 when x spans multiple lines. 35 36 # Inputs 37 38 `x` 39 40 : 1\. Function argument 41 42 # Type 43 44 ``` 45 singleton :: a -> [a] 46 ``` 47 48 # Examples 49 :::{.example} 50 ## `lib.lists.singleton` usage example 51 52 ```nix 53 singleton "foo" 54 => [ "foo" ] 55 ``` 56 57 ::: 58 */ 59 singleton = x: [ x ]; 60 61 /** 62 Apply the function to each element in the list. 63 Same as `map`, but arguments flipped. 64 65 # Inputs 66 67 `xs` 68 69 : 1\. Function argument 70 71 `f` 72 73 : 2\. Function argument 74 75 # Type 76 77 ``` 78 forEach :: [a] -> (a -> b) -> [b] 79 ``` 80 81 # Examples 82 :::{.example} 83 ## `lib.lists.forEach` usage example 84 85 ```nix 86 forEach [ 1 2 ] (x: 87 toString x 88 ) 89 => [ "1" "2" ] 90 ``` 91 92 ::: 93 */ 94 forEach = xs: f: map f xs; 95 96 /** 97 right fold a binary function `op` between successive elements of 98 `list` with `nul` as the starting value, i.e., 99 `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. 100 101 # Inputs 102 103 `op` 104 105 : 1\. Function argument 106 107 `nul` 108 109 : 2\. Function argument 110 111 `list` 112 113 : 3\. Function argument 114 115 # Type 116 117 ``` 118 foldr :: (a -> b -> b) -> b -> [a] -> b 119 ``` 120 121 # Examples 122 :::{.example} 123 ## `lib.lists.foldr` usage example 124 125 ```nix 126 concat = foldr (a: b: a + b) "z" 127 concat [ "a" "b" "c" ] 128 => "abcz" 129 # different types 130 strange = foldr (int: str: toString (int + 1) + str) "a" 131 strange [ 1 2 3 4 ] 132 => "2345a" 133 ``` 134 135 ::: 136 */ 137 foldr = 138 op: nul: list: 139 let 140 len = length list; 141 fold' = n: if n == len then nul else op (elemAt list n) (fold' (n + 1)); 142 in 143 fold' 0; 144 145 /** 146 `fold` is an alias of `foldr` for historic reasons. 147 148 ::: {.warning} 149 This function will be removed in 26.05. 150 ::: 151 */ 152 fold = warn "fold has been deprecated, use foldr instead" foldr; 153 154 /** 155 left fold, like `foldr`, but from the left: 156 157 `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`. 158 159 # Inputs 160 161 `op` 162 163 : 1\. Function argument 164 165 `nul` 166 167 : 2\. Function argument 168 169 `list` 170 171 : 3\. Function argument 172 173 # Type 174 175 ``` 176 foldl :: (b -> a -> b) -> b -> [a] -> b 177 ``` 178 179 # Examples 180 :::{.example} 181 ## `lib.lists.foldl` usage example 182 183 ```nix 184 lconcat = foldl (a: b: a + b) "z" 185 lconcat [ "a" "b" "c" ] 186 => "zabc" 187 # different types 188 lstrange = foldl (str: int: str + toString (int + 1)) "a" 189 lstrange [ 1 2 3 4 ] 190 => "a2345" 191 ``` 192 193 ::: 194 */ 195 foldl = 196 op: nul: list: 197 let 198 foldl' = n: if n == -1 then nul else op (foldl' (n - 1)) (elemAt list n); 199 in 200 foldl' (length list - 1); 201 202 /** 203 Reduce a list by applying a binary operator from left to right, 204 starting with an initial accumulator. 205 206 Before each application of the operator, the accumulator value is evaluated. 207 This behavior makes this function stricter than [`foldl`](#function-library-lib.lists.foldl). 208 209 Unlike [`builtins.foldl'`](https://nixos.org/manual/nix/unstable/language/builtins.html#builtins-foldl'), 210 the initial accumulator argument is evaluated before the first iteration. 211 212 A call like 213 214 ```nix 215 foldl' op acc [ x x x ... x x ] 216 ``` 217 218 is (denotationally) equivalent to the following, 219 but with the added benefit that `foldl'` itself will never overflow the stack. 220 221 ```nix 222 let 223 acc = builtins.seq acc (op acc x ); 224 acc = builtins.seq acc (op acc x ); 225 acc = builtins.seq acc (op acc x ); 226 ... 227 acc = builtins.seq acc (op acc x); 228 acc = builtins.seq acc (op acc x ); 229 in 230 acc 231 232 # Or ignoring builtins.seq 233 op (op (... (op (op (op acc x) x) x) ...) x) x 234 ``` 235 236 # Inputs 237 238 `op` 239 240 : The binary operation to run, where the two arguments are: 241 242 1. `acc`: The current accumulator value: Either the initial one for the first iteration, or the result of the previous iteration 243 2. `x`: The corresponding list element for this iteration 244 245 `acc` 246 247 : The initial accumulator value. 248 249 The accumulator value is evaluated in any case before the first iteration starts. 250 251 To avoid evaluation even before the `list` argument is given an eta expansion can be used: 252 253 ```nix 254 list: lib.foldl' op acc list 255 ``` 256 257 `list` 258 259 : The list to fold 260 261 # Type 262 263 ``` 264 foldl' :: (a -> b -> a) -> a -> [b] -> a 265 ``` 266 267 # Examples 268 :::{.example} 269 ## `lib.lists.foldl'` usage example 270 271 ```nix 272 foldl' (acc: x: acc + x) 0 [1 2 3] 273 => 6 274 ``` 275 276 ::: 277 */ 278 foldl' = 279 op: acc: 280 # The builtin `foldl'` is a bit lazier than one might expect. 281 # See https://github.com/NixOS/nix/pull/7158. 282 # In particular, the initial accumulator value is not forced before the first iteration starts. 283 builtins.seq acc (builtins.foldl' op acc); 284 285 /** 286 Map with index starting from 0 287 288 # Inputs 289 290 `f` 291 292 : 1\. Function argument 293 294 `list` 295 296 : 2\. Function argument 297 298 # Type 299 300 ``` 301 imap0 :: (Int -> a -> b) -> [a] -> [b] 302 ``` 303 304 # Examples 305 :::{.example} 306 ## `lib.lists.imap0` usage example 307 308 ```nix 309 imap0 (i: v: "${v}-${toString i}") ["a" "b"] 310 => [ "a-0" "b-1" ] 311 ``` 312 313 ::: 314 */ 315 imap0 = f: list: genList (n: f n (elemAt list n)) (length list); 316 317 /** 318 Map with index starting from 1 319 320 # Inputs 321 322 `f` 323 324 : 1\. Function argument 325 326 `list` 327 328 : 2\. Function argument 329 330 # Type 331 332 ``` 333 imap1 :: (Int -> a -> b) -> [a] -> [b] 334 ``` 335 336 # Examples 337 :::{.example} 338 ## `lib.lists.imap1` usage example 339 340 ```nix 341 imap1 (i: v: "${v}-${toString i}") ["a" "b"] 342 => [ "a-1" "b-2" ] 343 ``` 344 345 ::: 346 */ 347 imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list); 348 349 /** 350 Filter a list for elements that satisfy a predicate function. 351 The predicate function is called with both the index and value for each element. 352 It must return `true`/`false` to include/exclude a given element in the result. 353 This function is strict in the result of the predicate function for each element. 354 This function has O(n) complexity. 355 356 Also see [`builtins.filter`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filter) (available as `lib.lists.filter`), 357 which can be used instead when the index isn't needed. 358 359 # Inputs 360 361 `ipred` 362 363 : The predicate function, it takes two arguments: 364 - 1. (int): the index of the element. 365 - 2. (a): the value of the element. 366 367 It must return `true`/`false` to include/exclude a given element from the result. 368 369 `list` 370 371 : The list to filter using the predicate. 372 373 # Type 374 ``` 375 ifilter0 :: (Int -> a -> Bool) -> [a] -> [a] 376 ``` 377 378 # Examples 379 :::{.example} 380 ## `lib.lists.ifilter0` usage example 381 382 ```nix 383 ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ] 384 => [ 1 3 ] 385 ``` 386 ::: 387 */ 388 ifilter0 = 389 ipred: input: 390 map (idx: elemAt input idx) ( 391 filter (idx: ipred idx (elemAt input idx)) (genList (x: x) (length input)) 392 ); 393 394 /** 395 Map and concatenate the result. 396 397 # Type 398 399 ``` 400 concatMap :: (a -> [b]) -> [a] -> [b] 401 ``` 402 403 # Examples 404 :::{.example} 405 ## `lib.lists.concatMap` usage example 406 407 ```nix 408 concatMap (x: [x] ++ ["z"]) ["a" "b"] 409 => [ "a" "z" "b" "z" ] 410 ``` 411 412 ::: 413 */ 414 concatMap = builtins.concatMap; 415 416 /** 417 Flatten the argument into a single list; that is, nested lists are 418 spliced into the top-level lists. 419 420 # Inputs 421 422 `x` 423 424 : 1\. Function argument 425 426 # Type 427 428 ``` 429 flatten :: [a | [a | [a | ...]]] -> [a] 430 ``` 431 432 # Examples 433 :::{.example} 434 ## `lib.lists.flatten` usage example 435 436 ```nix 437 flatten [1 [2 [3] 4] 5] 438 => [1 2 3 4 5] 439 flatten 1 440 => [1] 441 ``` 442 443 ::: 444 */ 445 flatten = x: if isList x then concatMap (y: flatten y) x else [ x ]; 446 447 /** 448 Remove elements equal to `e` from a list. Useful for `buildInputs`. 449 450 # Inputs 451 452 `e` 453 454 : Element to remove from `list` 455 456 `list` 457 458 : The list 459 460 # Type 461 462 ``` 463 remove :: a -> [a] -> [a] 464 ``` 465 466 # Examples 467 :::{.example} 468 ## `lib.lists.remove` usage example 469 470 ```nix 471 remove 3 [ 1 3 4 3 ] 472 => [ 1 4 ] 473 ``` 474 475 ::: 476 */ 477 remove = e: filter (x: x != e); 478 479 /** 480 Find the sole element in the list matching the specified 481 predicate. 482 483 Returns `default` if no such element exists, or 484 `multiple` if there are multiple matching elements. 485 486 # Inputs 487 488 `pred` 489 490 : Predicate 491 492 `default` 493 494 : Default value to return if element was not found. 495 496 `multiple` 497 498 : Default value to return if more than one element was found 499 500 `list` 501 502 : Input list 503 504 # Type 505 506 ``` 507 findSingle :: (a -> Bool) -> a -> a -> [a] -> a 508 ``` 509 510 # Examples 511 :::{.example} 512 ## `lib.lists.findSingle` usage example 513 514 ```nix 515 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ] 516 => "multiple" 517 findSingle (x: x == 3) "none" "multiple" [ 1 3 ] 518 => 3 519 findSingle (x: x == 3) "none" "multiple" [ 1 9 ] 520 => "none" 521 ``` 522 523 ::: 524 */ 525 findSingle = 526 pred: default: multiple: list: 527 let 528 found = filter pred list; 529 len = length found; 530 in 531 if len == 0 then 532 default 533 else if len != 1 then 534 multiple 535 else 536 head found; 537 538 /** 539 Find the first index in the list matching the specified 540 predicate or return `default` if no such element exists. 541 542 # Inputs 543 544 `pred` 545 546 : Predicate 547 548 `default` 549 550 : Default value to return 551 552 `list` 553 554 : Input list 555 556 # Type 557 558 ``` 559 findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b) 560 ``` 561 562 # Examples 563 :::{.example} 564 ## `lib.lists.findFirstIndex` usage example 565 566 ```nix 567 findFirstIndex (x: x > 3) null [ 0 6 4 ] 568 => 1 569 findFirstIndex (x: x > 9) null [ 0 6 4 ] 570 => null 571 ``` 572 573 ::: 574 */ 575 findFirstIndex = 576 pred: default: list: 577 let 578 # A naive recursive implementation would be much simpler, but 579 # would also overflow the evaluator stack. We use `foldl'` as a workaround 580 # because it reuses the same stack space, evaluating the function for one 581 # element after another. We can't return early, so this means that we 582 # sacrifice early cutoff, but that appears to be an acceptable cost. A 583 # clever scheme with "exponential search" is possible, but appears over- 584 # engineered for now. See https://github.com/NixOS/nixpkgs/pull/235267 585 586 # Invariant: 587 # - if index < 0 then el == elemAt list (- index - 1) and all elements before el didn't satisfy pred 588 # - if index >= 0 then pred (elemAt list index) and all elements before (elemAt list index) didn't satisfy pred 589 # 590 # We start with index -1 and the 0'th element of the list, which satisfies the invariant 591 resultIndex = foldl' ( 592 index: el: 593 if index < 0 then 594 # No match yet before the current index, we need to check the element 595 if pred el then 596 # We have a match! Turn it into the actual index to prevent future iterations from modifying it 597 -index - 1 598 else 599 # Still no match, update the index to the next element (we're counting down, so minus one) 600 index - 1 601 else 602 # There's already a match, propagate the index without evaluating anything 603 index 604 ) (-1) list; 605 in 606 if resultIndex < 0 then default else resultIndex; 607 608 /** 609 Find the first element in the list matching the specified 610 predicate or return `default` if no such element exists. 611 612 # Inputs 613 614 `pred` 615 616 : Predicate 617 618 `default` 619 620 : Default value to return 621 622 `list` 623 624 : Input list 625 626 # Type 627 628 ``` 629 findFirst :: (a -> Bool) -> a -> [a] -> a 630 ``` 631 632 # Examples 633 :::{.example} 634 ## `lib.lists.findFirst` usage example 635 636 ```nix 637 findFirst (x: x > 3) 7 [ 1 6 4 ] 638 => 6 639 findFirst (x: x > 9) 7 [ 1 6 4 ] 640 => 7 641 ``` 642 643 ::: 644 */ 645 findFirst = 646 pred: default: list: 647 let 648 index = findFirstIndex pred null list; 649 in 650 if index == null then default else elemAt list index; 651 652 /** 653 Returns true if function `pred` returns true for at least one 654 element of `list`. 655 656 # Inputs 657 658 `pred` 659 660 : Predicate 661 662 `list` 663 664 : Input list 665 666 # Type 667 668 ``` 669 any :: (a -> Bool) -> [a] -> Bool 670 ``` 671 672 # Examples 673 :::{.example} 674 ## `lib.lists.any` usage example 675 676 ```nix 677 any isString [ 1 "a" { } ] 678 => true 679 any isString [ 1 { } ] 680 => false 681 ``` 682 683 ::: 684 */ 685 any = builtins.any; 686 687 /** 688 Returns true if function `pred` returns true for all elements of 689 `list`. 690 691 # Inputs 692 693 `pred` 694 695 : Predicate 696 697 `list` 698 699 : Input list 700 701 # Type 702 703 ``` 704 all :: (a -> Bool) -> [a] -> Bool 705 ``` 706 707 # Examples 708 :::{.example} 709 ## `lib.lists.all` usage example 710 711 ```nix 712 all (x: x < 3) [ 1 2 ] 713 => true 714 all (x: x < 3) [ 1 2 3 ] 715 => false 716 ``` 717 718 ::: 719 */ 720 all = builtins.all; 721 722 /** 723 Count how many elements of `list` match the supplied predicate 724 function. 725 726 # Inputs 727 728 `pred` 729 730 : Predicate 731 732 # Type 733 734 ``` 735 count :: (a -> Bool) -> [a] -> Int 736 ``` 737 738 # Examples 739 :::{.example} 740 ## `lib.lists.count` usage example 741 742 ```nix 743 count (x: x == 3) [ 3 2 3 4 6 ] 744 => 2 745 ``` 746 747 ::: 748 */ 749 count = pred: foldl' (c: x: if pred x then c + 1 else c) 0; 750 751 /** 752 Return a singleton list or an empty list, depending on a boolean 753 value. Useful when building lists with optional elements 754 (e.g. `++ optional (system == "i686-linux") firefox`). 755 756 # Inputs 757 758 `cond` 759 760 : 1\. Function argument 761 762 `elem` 763 764 : 2\. Function argument 765 766 # Type 767 768 ``` 769 optional :: Bool -> a -> [a] 770 ``` 771 772 # Examples 773 :::{.example} 774 ## `lib.lists.optional` usage example 775 776 ```nix 777 optional true "foo" 778 => [ "foo" ] 779 optional false "foo" 780 => [ ] 781 ``` 782 783 ::: 784 */ 785 optional = cond: elem: if cond then [ elem ] else [ ]; 786 787 /** 788 Returns a list or an empty list, depending on a boolean value. 789 790 # Inputs 791 792 `cond` 793 794 : Condition 795 796 `elems` 797 798 : List to return if condition is true 799 800 # Type 801 802 ``` 803 optionals :: Bool -> [a] -> [a] 804 ``` 805 806 # Examples 807 :::{.example} 808 ## `lib.lists.optionals` usage example 809 810 ```nix 811 optionals true [ 2 3 ] 812 => [ 2 3 ] 813 optionals false [ 2 3 ] 814 => [ ] 815 ``` 816 817 ::: 818 */ 819 optionals = cond: elems: if cond then elems else [ ]; 820 821 /** 822 If argument is a list, return it; else, wrap it in a singleton 823 list. If you're using this, you should almost certainly 824 reconsider if there isn't a more "well-typed" approach. 825 826 # Inputs 827 828 `x` 829 830 : 1\. Function argument 831 832 # Type 833 834 ``` 835 toList :: (a | [a]) -> [a] 836 ``` 837 838 # Examples 839 :::{.example} 840 ## `lib.lists.toList` usage example 841 842 ```nix 843 toList [ 1 2 ] 844 => [ 1 2 ] 845 toList "hi" 846 => [ "hi" ] 847 ``` 848 849 ::: 850 */ 851 toList = x: if isList x then x else [ x ]; 852 853 /** 854 Returns a list of integers from `first` up to and including `last`. 855 856 # Inputs 857 858 `first` 859 860 : First integer in the range 861 862 `last` 863 864 : Last integer in the range 865 866 # Type 867 868 ``` 869 range :: Int -> Int -> [Int] 870 ``` 871 872 # Examples 873 :::{.example} 874 ## `lib.lists.range` usage example 875 876 ```nix 877 range 2 4 878 => [ 2 3 4 ] 879 range 3 2 880 => [ ] 881 ``` 882 883 ::: 884 */ 885 range = first: last: if first > last then [ ] else genList (n: first + n) (last - first + 1); 886 887 /** 888 Returns a list with `n` copies of an element. 889 890 # Inputs 891 892 `n` 893 894 : 1\. Function argument 895 896 `elem` 897 898 : 2\. Function argument 899 900 # Type 901 902 ``` 903 replicate :: Int -> a -> [a] 904 ``` 905 906 # Examples 907 :::{.example} 908 ## `lib.lists.replicate` usage example 909 910 ```nix 911 replicate 3 "a" 912 => [ "a" "a" "a" ] 913 replicate 2 true 914 => [ true true ] 915 ``` 916 917 ::: 918 */ 919 replicate = n: elem: genList (_: elem) n; 920 921 /** 922 Splits the elements of a list in two lists, `right` and 923 `wrong`, depending on the evaluation of a predicate. 924 925 # Inputs 926 927 `pred` 928 929 : Predicate 930 931 `list` 932 933 : Input list 934 935 # Type 936 937 ``` 938 partition :: (a -> Bool) -> [a] -> { right :: [a]; wrong :: [a]; } 939 ``` 940 941 # Examples 942 :::{.example} 943 ## `lib.lists.partition` usage example 944 945 ```nix 946 partition (x: x > 2) [ 5 1 2 3 4 ] 947 => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; } 948 ``` 949 950 ::: 951 */ 952 partition = builtins.partition; 953 954 /** 955 Splits the elements of a list into many lists, using the return value of a predicate. 956 Predicate should return a string which becomes keys of attrset `groupBy` returns. 957 `groupBy'` allows to customise the combining function and initial value 958 959 # Inputs 960 961 `op` 962 963 : 1\. Function argument 964 965 `nul` 966 967 : 2\. Function argument 968 969 `pred` 970 971 : 3\. Function argument 972 973 `lst` 974 975 : 4\. Function argument 976 977 # Type 978 979 ``` 980 groupBy' :: (a -> b -> a) -> a -> (b -> String) -> [b] -> { [String] :: a } 981 ``` 982 983 # Examples 984 :::{.example} 985 ## `lib.lists.groupBy'` usage example 986 987 ```nix 988 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] 989 => { true = [ 5 3 4 ]; false = [ 1 2 ]; } 990 groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";} 991 {name = "xfce"; script = "xfce4-session &";} 992 {name = "icewm"; script = "icewmbg &";} 993 {name = "mate"; script = "gnome-session &";} 994 ] 995 => { icewm = [ { name = "icewm"; script = "icewm &"; } 996 { name = "icewm"; script = "icewmbg &"; } ]; 997 mate = [ { name = "mate"; script = "gnome-session &"; } ]; 998 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ]; 999 } 1000 1001 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] 1002 => { true = 12; false = 3; } 1003 ``` 1004 1005 ::: 1006 */ 1007 groupBy' = 1008 op: nul: pred: lst: 1009 mapAttrs (name: foldl op nul) (groupBy pred lst); 1010 1011 groupBy = 1012 builtins.groupBy or ( 1013 pred: 1014 foldl' ( 1015 r: e: 1016 let 1017 key = pred e; 1018 in 1019 r // { ${key} = (r.${key} or [ ]) ++ [ e ]; } 1020 ) { } 1021 ); 1022 1023 /** 1024 Merges two lists of the same size together. If the sizes aren't the same 1025 the merging stops at the shortest. How both lists are merged is defined 1026 by the first argument. 1027 1028 # Inputs 1029 1030 `f` 1031 1032 : Function to zip elements of both lists 1033 1034 `fst` 1035 1036 : First list 1037 1038 `snd` 1039 1040 : Second list 1041 1042 # Type 1043 1044 ``` 1045 zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c] 1046 ``` 1047 1048 # Examples 1049 :::{.example} 1050 ## `lib.lists.zipListsWith` usage example 1051 1052 ```nix 1053 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] 1054 => ["he" "lo"] 1055 ``` 1056 1057 ::: 1058 */ 1059 zipListsWith = 1060 f: fst: snd: 1061 genList (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd)); 1062 1063 /** 1064 Merges two lists of the same size together. If the sizes aren't the same 1065 the merging stops at the shortest. 1066 1067 # Inputs 1068 1069 `fst` 1070 1071 : First list 1072 1073 `snd` 1074 1075 : Second list 1076 1077 # Type 1078 1079 ``` 1080 zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }] 1081 ``` 1082 1083 # Examples 1084 :::{.example} 1085 ## `lib.lists.zipLists` usage example 1086 1087 ```nix 1088 zipLists [ 1 2 ] [ "a" "b" ] 1089 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ] 1090 ``` 1091 1092 ::: 1093 */ 1094 zipLists = zipListsWith (fst: snd: { inherit fst snd; }); 1095 1096 /** 1097 Reverse the order of the elements of a list. 1098 1099 # Inputs 1100 1101 `xs` 1102 1103 : 1\. Function argument 1104 1105 # Type 1106 1107 ``` 1108 reverseList :: [a] -> [a] 1109 ``` 1110 1111 # Examples 1112 :::{.example} 1113 ## `lib.lists.reverseList` usage example 1114 1115 ```nix 1116 reverseList [ "b" "o" "j" ] 1117 => [ "j" "o" "b" ] 1118 ``` 1119 1120 ::: 1121 */ 1122 reverseList = 1123 xs: 1124 let 1125 l = length xs; 1126 in 1127 genList (n: elemAt xs (l - n - 1)) l; 1128 1129 /** 1130 Depth-First Search (DFS) for lists `list != []`. 1131 1132 `before a b == true` means that `b` depends on `a` (there's an 1133 edge from `b` to `a`). 1134 1135 # Inputs 1136 1137 `stopOnCycles` 1138 1139 : 1\. Function argument 1140 1141 `before` 1142 1143 : 2\. Function argument 1144 1145 `list` 1146 1147 : 3\. Function argument 1148 1149 # Type 1150 1151 ``` 1152 listDfs :: Bool -> (a -> a -> Bool) -> [a] -> ({ minimal :: a; visited :: [a]; rest :: [a]; } | { cycle :: a; loops :: [a]; visited :: [a]; rest :: [a]; }) 1153 ``` 1154 1155 # Examples 1156 :::{.example} 1157 ## `lib.lists.listDfs` usage example 1158 1159 ```nix 1160 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ] 1161 == { minimal = "/"; # minimal element 1162 visited = [ "/home/user" ]; # seen elements (in reverse order) 1163 rest = [ "/home" "other" ]; # everything else 1164 } 1165 1166 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ] 1167 == { cycle = "/"; # cycle encountered at this element 1168 loops = [ "/" ]; # and continues to these elements 1169 visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order) 1170 rest = [ "/home" "other" ]; # everything else 1171 ``` 1172 1173 ::: 1174 */ 1175 listDfs = 1176 stopOnCycles: before: list: 1177 let 1178 dfs' = 1179 us: visited: rest: 1180 let 1181 c = filter (x: before x us) visited; 1182 b = partition (x: before x us) rest; 1183 in 1184 if stopOnCycles && (length c > 0) then 1185 { 1186 cycle = us; 1187 loops = c; 1188 inherit visited rest; 1189 } 1190 else if length b.right == 0 then 1191 # nothing is before us 1192 { 1193 minimal = us; 1194 inherit visited rest; 1195 } 1196 else 1197 # grab the first one before us and continue 1198 dfs' (head b.right) ([ us ] ++ visited) (tail b.right ++ b.wrong); 1199 in 1200 dfs' (head list) [ ] (tail list); 1201 1202 /** 1203 Sort a list based on a partial ordering using DFS. This 1204 implementation is O(N^2), if your ordering is linear, use `sort` 1205 instead. 1206 1207 `before a b == true` means that `b` should be after `a` 1208 in the result. 1209 1210 # Inputs 1211 1212 `before` 1213 1214 : 1\. Function argument 1215 1216 `list` 1217 1218 : 2\. Function argument 1219 1220 # Type 1221 1222 ``` 1223 toposort :: (a -> a -> Bool) -> [a] -> ({ result :: [a]; } | { cycle :: [a]; loops :: [a]; }) 1224 ``` 1225 1226 # Examples 1227 :::{.example} 1228 ## `lib.lists.toposort` usage example 1229 1230 ```nix 1231 toposort hasPrefix [ "/home/user" "other" "/" "/home" ] 1232 == { result = [ "/" "/home" "/home/user" "other" ]; } 1233 1234 toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ] 1235 == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle 1236 loops = [ "/" ]; } # loops back to these elements 1237 1238 toposort hasPrefix [ "other" "/home/user" "/home" "/" ] 1239 == { result = [ "other" "/" "/home" "/home/user" ]; } 1240 1241 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; } 1242 ``` 1243 1244 ::: 1245 */ 1246 toposort = 1247 before: list: 1248 let 1249 dfsthis = listDfs true before list; 1250 toporest = toposort before (dfsthis.visited ++ dfsthis.rest); 1251 in 1252 if length list < 2 then 1253 # finish 1254 { result = list; } 1255 else if dfsthis ? cycle then 1256 # there's a cycle, starting from the current vertex, return it 1257 { 1258 cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited); 1259 inherit (dfsthis) loops; 1260 } 1261 else if toporest ? cycle then 1262 # there's a cycle somewhere else in the graph, return it 1263 toporest 1264 # Slow, but short. Can be made a bit faster with an explicit stack. 1265 else 1266 # there are no cycles 1267 { result = [ dfsthis.minimal ] ++ toporest.result; }; 1268 1269 /** 1270 Sort a list based on a comparator function which compares two 1271 elements and returns true if the first argument is strictly below 1272 the second argument. The returned list is sorted in an increasing 1273 order. The implementation does a quick-sort. 1274 1275 See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the 1276 default comparison on a function-derived property, and may be more efficient. 1277 1278 # Inputs 1279 1280 `comparator` 1281 1282 : 1\. Function argument 1283 1284 `list` 1285 1286 : 2\. Function argument 1287 1288 # Type 1289 1290 ``` 1291 sort :: (a -> a -> Bool) -> [a] -> [a] 1292 ``` 1293 1294 # Examples 1295 :::{.example} 1296 ## `lib.lists.sort` usage example 1297 1298 ```nix 1299 sort (p: q: p < q) [ 5 3 7 ] 1300 => [ 3 5 7 ] 1301 ``` 1302 1303 ::: 1304 */ 1305 sort = builtins.sort; 1306 1307 /** 1308 Sort a list based on the default comparison of a derived property `b`. 1309 1310 The items are returned in `b`-increasing order. 1311 1312 **Performance**: 1313 1314 The passed function `f` is only evaluated once per item, 1315 unlike an unprepared [`sort`](#function-library-lib.lists.sort) using 1316 `f p < f q`. 1317 1318 **Laws**: 1319 ```nix 1320 sortOn f == sort (p: q: f p < f q) 1321 ``` 1322 1323 # Inputs 1324 1325 `f` 1326 1327 : 1\. Function argument 1328 1329 `list` 1330 1331 : 2\. Function argument 1332 1333 # Type 1334 1335 ``` 1336 sortOn :: (a -> b) -> [a] -> [a], for comparable b 1337 ``` 1338 1339 # Examples 1340 :::{.example} 1341 ## `lib.lists.sortOn` usage example 1342 1343 ```nix 1344 sortOn stringLength [ "aa" "b" "cccc" ] 1345 => [ "b" "aa" "cccc" ] 1346 ``` 1347 1348 ::: 1349 */ 1350 sortOn = 1351 f: list: 1352 let 1353 # Heterogenous list as pair may be ugly, but requires minimal allocations. 1354 pairs = map (x: [ 1355 (f x) 1356 x 1357 ]) list; 1358 in 1359 map (x: builtins.elemAt x 1) ( 1360 sort 1361 # Compare the first element of the pairs 1362 # Do not factor out the `<`, to avoid calls in hot code; duplicate instead. 1363 (a: b: head a < head b) 1364 pairs 1365 ); 1366 1367 /** 1368 Compare two lists element-by-element with a comparison function `cmp`. 1369 1370 List elements are compared pairwise in order by the provided comparison function `cmp`, 1371 the first non-equal pair of elements determines the result. 1372 1373 :::{.note} 1374 The `<` operator can also be used to compare lists using a boolean condition. (e.g. `[1 2] < [1 3]` is `true`). 1375 See also [language operators](https://nix.dev/manual/nix/stable/language/operators#comparison) for more information. 1376 ::: 1377 1378 # Inputs 1379 1380 `cmp` 1381 1382 : The comparison function `a: b: ...` must return: 1383 - `0` if `a` and `b` are equal 1384 - `1` if `a` is greater than `b` 1385 - `-1` if `a` is less than `b` 1386 1387 See [lib.compare](#function-library-lib.trivial.compare) for a an example implementation. 1388 1389 `a` 1390 1391 : The first list 1392 1393 `b` 1394 1395 : The second list 1396 1397 # Type 1398 1399 ``` 1400 compareLists :: (a -> a -> Int) -> [a] -> [a] -> Int 1401 ``` 1402 1403 # Examples 1404 :::{.example} 1405 ## `lib.lists.compareLists` usage examples 1406 1407 ```nix 1408 compareLists lib.compare [] [] 1409 => 0 1410 compareLists lib.compare [] [ "a" ] 1411 => -1 1412 compareLists lib.compare [ "a" ] [] 1413 => 1 1414 compareLists lib.compare [ "a" "b" ] [ "a" "c" ] 1415 => -1 1416 ``` 1417 1418 ::: 1419 */ 1420 compareLists = 1421 cmp: a: b: 1422 if a == [ ] then 1423 if b == [ ] then 0 else -1 1424 else if b == [ ] then 1425 1 1426 else 1427 let 1428 rel = cmp (head a) (head b); 1429 in 1430 if rel == 0 then compareLists cmp (tail a) (tail b) else rel; 1431 1432 /** 1433 Sort list using "Natural sorting". 1434 Numeric portions of strings are sorted in numeric order. 1435 1436 # Inputs 1437 1438 `lst` 1439 1440 : 1\. Function argument 1441 1442 # Type 1443 1444 ``` 1445 naturalSort :: [String] -> [String] 1446 ``` 1447 1448 # Examples 1449 :::{.example} 1450 ## `lib.lists.naturalSort` usage example 1451 1452 ```nix 1453 naturalSort ["disk11" "disk8" "disk100" "disk9"] 1454 => ["disk8" "disk9" "disk11" "disk100"] 1455 naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"] 1456 => ["10.5.16.62" "10.46.133.149" "10.54.16.25"] 1457 naturalSort ["v0.2" "v0.15" "v0.0.9"] 1458 => [ "v0.0.9" "v0.2" "v0.15" ] 1459 ``` 1460 1461 ::: 1462 */ 1463 naturalSort = 1464 lst: 1465 let 1466 vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s); 1467 prepared = map (x: [ 1468 (vectorise x) 1469 x 1470 ]) lst; # remember vectorised version for O(n) regex splits 1471 less = a: b: (compareLists compare (head a) (head b)) < 0; 1472 in 1473 map (x: elemAt x 1) (sort less prepared); 1474 1475 /** 1476 Returns the first (at most) N elements of a list. 1477 1478 # Inputs 1479 1480 `count` 1481 1482 : Number of elements to take 1483 1484 `list` 1485 1486 : Input list 1487 1488 # Type 1489 1490 ``` 1491 take :: Int -> [a] -> [a] 1492 ``` 1493 1494 # Examples 1495 :::{.example} 1496 ## `lib.lists.take` usage example 1497 1498 ```nix 1499 take 2 [ "a" "b" "c" "d" ] 1500 => [ "a" "b" ] 1501 take 2 [ ] 1502 => [ ] 1503 ``` 1504 1505 ::: 1506 */ 1507 take = count: sublist 0 count; 1508 1509 /** 1510 Returns the last (at most) N elements of a list. 1511 1512 # Inputs 1513 1514 `count` 1515 1516 : Maximum number of elements to pick 1517 1518 `list` 1519 1520 : Input list 1521 1522 # Type 1523 1524 ``` 1525 takeEnd :: Int -> [a] -> [a] 1526 ``` 1527 1528 # Examples 1529 :::{.example} 1530 ## `lib.lists.takeEnd` usage example 1531 1532 ```nix 1533 takeEnd 2 [ "a" "b" "c" "d" ] 1534 => [ "c" "d" ] 1535 takeEnd 2 [ ] 1536 => [ ] 1537 ``` 1538 1539 ::: 1540 */ 1541 takeEnd = n: xs: drop (max 0 (length xs - n)) xs; 1542 1543 /** 1544 Remove the first (at most) N elements of a list. 1545 1546 # Inputs 1547 1548 `count` 1549 1550 : Number of elements to drop 1551 1552 `list` 1553 1554 : Input list 1555 1556 # Type 1557 1558 ``` 1559 drop :: Int -> [a] -> [a] 1560 ``` 1561 1562 # Examples 1563 :::{.example} 1564 ## `lib.lists.drop` usage example 1565 1566 ```nix 1567 drop 2 [ "a" "b" "c" "d" ] 1568 => [ "c" "d" ] 1569 drop 2 [ ] 1570 => [ ] 1571 ``` 1572 1573 ::: 1574 */ 1575 drop = count: list: sublist count (length list) list; 1576 1577 /** 1578 Remove the last (at most) N elements of a list. 1579 1580 # Inputs 1581 1582 `count` 1583 1584 : Number of elements to drop 1585 1586 `list` 1587 1588 : Input list 1589 1590 # Type 1591 1592 ``` 1593 dropEnd :: Int -> [a] -> [a] 1594 ``` 1595 1596 # Examples 1597 1598 :::{.example} 1599 ## `lib.lists.dropEnd` usage example 1600 1601 ```nix 1602 dropEnd 2 [ "a" "b" "c" "d" ] 1603 => [ "a" "b" ] 1604 dropEnd 2 [ ] 1605 => [ ] 1606 ``` 1607 ::: 1608 */ 1609 dropEnd = n: xs: take (max 0 (length xs - n)) xs; 1610 1611 /** 1612 Whether the first list is a prefix of the second list. 1613 1614 # Inputs 1615 1616 `list1` 1617 1618 : 1\. Function argument 1619 1620 `list2` 1621 1622 : 2\. Function argument 1623 1624 # Type 1625 1626 ``` 1627 hasPrefix :: [a] -> [a] -> Bool 1628 ``` 1629 1630 # Examples 1631 :::{.example} 1632 ## `lib.lists.hasPrefix` usage example 1633 1634 ```nix 1635 hasPrefix [ 1 2 ] [ 1 2 3 4 ] 1636 => true 1637 hasPrefix [ 0 1 ] [ 1 2 3 4 ] 1638 => false 1639 ``` 1640 1641 ::: 1642 */ 1643 hasPrefix = list1: list2: take (length list1) list2 == list1; 1644 1645 /** 1646 Remove the first list as a prefix from the second list. 1647 Error if the first list isn't a prefix of the second list. 1648 1649 # Inputs 1650 1651 `list1` 1652 1653 : 1\. Function argument 1654 1655 `list2` 1656 1657 : 2\. Function argument 1658 1659 # Type 1660 1661 ``` 1662 removePrefix :: [a] -> [a] -> [a] 1663 ``` 1664 1665 # Examples 1666 :::{.example} 1667 ## `lib.lists.removePrefix` usage example 1668 1669 ```nix 1670 removePrefix [ 1 2 ] [ 1 2 3 4 ] 1671 => [ 3 4 ] 1672 removePrefix [ 0 1 ] [ 1 2 3 4 ] 1673 => <error> 1674 ``` 1675 1676 ::: 1677 */ 1678 removePrefix = 1679 list1: list2: 1680 if hasPrefix list1 list2 then 1681 drop (length list1) list2 1682 else 1683 throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument"; 1684 1685 /** 1686 Returns a list consisting of at most `count` elements of `list`, 1687 starting at index `start`. 1688 1689 # Inputs 1690 1691 `start` 1692 1693 : Index at which to start the sublist 1694 1695 `count` 1696 1697 : Number of elements to take 1698 1699 `list` 1700 1701 : Input list 1702 1703 # Type 1704 1705 ``` 1706 sublist :: Int -> Int -> [a] -> [a] 1707 ``` 1708 1709 # Examples 1710 :::{.example} 1711 ## `lib.lists.sublist` usage example 1712 1713 ```nix 1714 sublist 1 3 [ "a" "b" "c" "d" "e" ] 1715 => [ "b" "c" "d" ] 1716 sublist 1 3 [ ] 1717 => [ ] 1718 ``` 1719 1720 ::: 1721 */ 1722 sublist = 1723 start: count: list: 1724 let 1725 len = length list; 1726 in 1727 genList (n: elemAt list (n + start)) ( 1728 if start >= len then 1729 0 1730 else if start + count > len then 1731 len - start 1732 else 1733 count 1734 ); 1735 1736 /** 1737 The common prefix of two lists. 1738 1739 # Inputs 1740 1741 `list1` 1742 1743 : 1\. Function argument 1744 1745 `list2` 1746 1747 : 2\. Function argument 1748 1749 # Type 1750 1751 ``` 1752 commonPrefix :: [a] -> [a] -> [a] 1753 ``` 1754 1755 # Examples 1756 :::{.example} 1757 ## `lib.lists.commonPrefix` usage example 1758 1759 ```nix 1760 commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ] 1761 => [ 1 2 ] 1762 commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ] 1763 => [ 1 2 3 ] 1764 commonPrefix [ 1 2 3 ] [ 4 5 6 ] 1765 => [ ] 1766 ``` 1767 1768 ::: 1769 */ 1770 commonPrefix = 1771 list1: list2: 1772 let 1773 # Zip the lists together into a list of booleans whether each element matches 1774 matchings = zipListsWith (fst: snd: fst != snd) list1 list2; 1775 # Find the first index where the elements don't match, 1776 # which will then also be the length of the common prefix. 1777 # If all elements match, we fall back to the length of the zipped list, 1778 # which is the same as the length of the smaller list. 1779 commonPrefixLength = findFirstIndex id (length matchings) matchings; 1780 in 1781 take commonPrefixLength list1; 1782 1783 /** 1784 Returns the last element of a list. 1785 1786 This function throws an error if the list is empty. 1787 1788 # Inputs 1789 1790 `list` 1791 1792 : 1\. Function argument 1793 1794 # Type 1795 1796 ``` 1797 last :: [a] -> a 1798 ``` 1799 1800 # Examples 1801 :::{.example} 1802 ## `lib.lists.last` usage example 1803 1804 ```nix 1805 last [ 1 2 3 ] 1806 => 3 1807 ``` 1808 1809 ::: 1810 */ 1811 last = 1812 list: 1813 assert lib.assertMsg (list != [ ]) "lists.last: list must not be empty!"; 1814 elemAt list (length list - 1); 1815 1816 /** 1817 Returns all elements but the last. 1818 1819 This function throws an error if the list is empty. 1820 1821 # Inputs 1822 1823 `list` 1824 1825 : 1\. Function argument 1826 1827 # Type 1828 1829 ``` 1830 init :: [a] -> [a] 1831 ``` 1832 1833 # Examples 1834 :::{.example} 1835 ## `lib.lists.init` usage example 1836 1837 ```nix 1838 init [ 1 2 3 ] 1839 => [ 1 2 ] 1840 ``` 1841 1842 ::: 1843 */ 1844 init = 1845 list: 1846 assert lib.assertMsg (list != [ ]) "lists.init: list must not be empty!"; 1847 take (length list - 1) list; 1848 1849 /** 1850 Returns the image of the cross product of some lists by a function. 1851 1852 # Examples 1853 :::{.example} 1854 ## `lib.lists.crossLists` usage example 1855 1856 ```nix 1857 crossLists (x: y: "${toString x}${toString y}") [[1 2] [3 4]] 1858 => [ "13" "14" "23" "24" ] 1859 ``` 1860 1861 If you have an attrset already, consider mapCartesianProduct: 1862 1863 ```nix 1864 mapCartesianProduct (x: "${toString x.a}${toString x.b}") { a = [1 2]; b = [3 4]; } 1865 => [ "13" "14" "23" "24" ] 1866 ``` 1867 ::: 1868 */ 1869 crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [ f ]; 1870 1871 /** 1872 Remove duplicate elements from the `list`. O(n^2) complexity. 1873 1874 :::{.note} 1875 If the list only contains strings and order is not important, the complexity can be reduced to O(n log n) by using [`lib.lists.uniqueStrings`](#function-library-lib.lists.uniqueStrings) instead. 1876 ::: 1877 1878 # Inputs 1879 1880 `list` 1881 1882 : Input list 1883 1884 # Type 1885 1886 ``` 1887 unique :: [a] -> [a] 1888 ``` 1889 1890 # Examples 1891 :::{.example} 1892 ## `lib.lists.unique` usage example 1893 1894 ```nix 1895 unique [ 3 2 3 4 ] 1896 => [ 3 2 4 ] 1897 ``` 1898 1899 ::: 1900 */ 1901 unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [ ]; 1902 1903 /** 1904 Removes duplicate strings from the `list`. O(n log n) complexity. 1905 1906 :::{.note} 1907 Order is not preserved. 1908 1909 All elements of the list must be strings without context. 1910 1911 This function fails when the list contains a non-string element or a [string with context](https://nix.dev/manual/nix/latest/language/string-context.html). 1912 In that case use [`lib.lists.unique`](#function-library-lib.lists.unique) instead. 1913 ::: 1914 1915 # Inputs 1916 1917 `list` 1918 1919 : List of strings 1920 1921 # Type 1922 1923 ``` 1924 uniqueStrings :: [String] -> [String] 1925 ``` 1926 1927 # Examples 1928 :::{.example} 1929 ## `lib.lists.uniqueStrings` usage example 1930 1931 ```nix 1932 uniqueStrings [ "foo" "bar" "foo" ] 1933 => [ "bar" "foo" ] # order is not preserved 1934 ``` 1935 1936 ::: 1937 */ 1938 uniqueStrings = list: attrNames (groupBy id list); 1939 1940 /** 1941 Check if list contains only unique elements. O(n^2) complexity. 1942 1943 # Inputs 1944 1945 `list` 1946 1947 : 1\. Function argument 1948 1949 # Type 1950 1951 ``` 1952 allUnique :: [a] -> Bool 1953 ``` 1954 1955 # Examples 1956 :::{.example} 1957 ## `lib.lists.allUnique` usage example 1958 1959 ```nix 1960 allUnique [ 3 2 3 4 ] 1961 => false 1962 allUnique [ 3 2 4 1 ] 1963 => true 1964 ``` 1965 1966 ::: 1967 */ 1968 allUnique = list: (length (unique list) == length list); 1969 1970 /** 1971 Intersects list `list1` and another list (`list2`). 1972 1973 O(nm) complexity. 1974 1975 # Inputs 1976 1977 `list1` 1978 1979 : First list 1980 1981 `list2` 1982 1983 : Second list 1984 1985 # Type 1986 1987 ``` 1988 intersectLists :: [a] -> [a] -> [a] 1989 ``` 1990 1991 # Examples 1992 :::{.example} 1993 ## `lib.lists.intersectLists` usage example 1994 1995 ```nix 1996 intersectLists [ 1 2 3 ] [ 6 3 2 ] 1997 => [ 3 2 ] 1998 ``` 1999 2000 ::: 2001 */ 2002 intersectLists = e: filter (x: elem x e); 2003 2004 /** 2005 Subtracts list `e` from another list (`list2`). 2006 2007 O(nm) complexity. 2008 2009 # Inputs 2010 2011 `e` 2012 2013 : First list 2014 2015 `list2` 2016 2017 : Second list 2018 2019 # Type 2020 2021 ``` 2022 subtractLists :: [a] -> [a] -> [a] 2023 ``` 2024 2025 # Examples 2026 :::{.example} 2027 ## `lib.lists.subtractLists` usage example 2028 2029 ```nix 2030 subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ] 2031 => [ 1 4 5 ] 2032 ``` 2033 2034 ::: 2035 */ 2036 subtractLists = e: filter (x: !(elem x e)); 2037 2038 /** 2039 Test if two lists have no common element. 2040 It should be slightly more efficient than `intersectLists a b == []`. 2041 2042 # Inputs 2043 2044 `a` 2045 2046 : 1\. Function argument 2047 2048 `b` 2049 2050 : 2\. Function argument 2051 2052 # Type 2053 2054 ``` 2055 mutuallyExclusive :: [a] -> [a] -> Bool 2056 ``` 2057 */ 2058 mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b); 2059 2060 /** 2061 Concatenate all attributes of an attribute set. 2062 This assumes that every attribute of the set is a list. 2063 2064 # Inputs 2065 2066 `set` 2067 2068 : Attribute set with attributes that are lists 2069 2070 # Type 2071 2072 ``` 2073 concatAttrValues :: { [String] :: [a] } -> [a] 2074 ``` 2075 2076 # Examples 2077 :::{.example} 2078 ## `lib.concatAttrValues` usage example 2079 2080 ```nix 2081 concatAttrValues { a = [ 1 2 ]; b = [ 3 ]; } 2082 => [ 1 2 3 ] 2083 ``` 2084 2085 ::: 2086 */ 2087 concatAttrValues = set: concatLists (attrValues set); 2088 2089 /** 2090 Replaces a list's nth element with a new element 2091 2092 # Inputs 2093 2094 `list` 2095 : Input list 2096 2097 `idx` 2098 : index to replace 2099 2100 `newElem` 2101 : new element to replace with 2102 2103 # Type 2104 2105 ``` 2106 replaceElemAt :: [a] -> Int -> a -> [a] 2107 ``` 2108 2109 # Examples 2110 :::{.example} 2111 ## `replaceElemAt` usage example 2112 2113 ```nix 2114 lib.replaceElemAt` [1 2 3] 0 "a" 2115 => ["a" 2 3] 2116 ``` 2117 2118 ::: 2119 */ 2120 replaceElemAt = 2121 list: idx: newElem: 2122 assert lib.assertMsg (idx >= 0 && idx < length list) 2123 "'lists.replaceElemAt' called with index ${toString idx} on a list of size ${toString (length list)}"; 2124 genList (i: if i == idx then newElem else elemAt list i) (length list); 2125}