From bccab965b9226e7d515e1ee1cdf47bb32d1df63d Mon Sep 17 00:00:00 2001 From: Jan Malakhovski Date: Thu, 7 Dec 2017 21:26:30 +0000 Subject: [PATCH] lib: implement `compare`, `splitByAndCompare`, and `compareLists` --- lib/default.nix | 6 +++--- lib/lists.nix | 24 ++++++++++++++++++++++++ lib/trivial.nix | 25 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index 9dc4fea99fc2..eb19dc06ce80 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -56,7 +56,7 @@ let replaceStrings seq stringLength sub substring tail; inherit (trivial) id const concat or and boolToString mergeAttrs flip mapNullable inNixShell min max importJSON warn info - nixpkgsVersion mod; + nixpkgsVersion mod compare splitByAndCompare; inherit (fixedPoints) fix fix' extends composeExtensions makeExtensible makeExtensibleWithCustomName; @@ -71,8 +71,8 @@ let inherit (lists) singleton foldr fold foldl foldl' imap0 imap1 concatMap flatten remove findSingle findFirst any all count optional optionals toList range partition zipListsWith zipLists - reverseList listDfs toposort sort take drop sublist last init - crossLists unique intersectLists subtractLists + reverseList listDfs toposort sort compareLists take drop sublist + last init crossLists unique intersectLists subtractLists mutuallyExclusive; inherit (strings) concatStrings concatMapStrings concatImapStrings intersperse concatStringsSep concatMapStringsSep diff --git a/lib/lists.nix b/lib/lists.nix index 8f67c6bb0ca3..f7e09040a5aa 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -385,6 +385,30 @@ rec { if len < 2 then list else (sort strictLess pivot.left) ++ [ first ] ++ (sort strictLess pivot.right)); + /* 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; + /* Return the first (at most) N elements of a list. Example: diff --git a/lib/trivial.nix b/lib/trivial.nix index c452c7b65bc1..5f18c0b61cc0 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -81,6 +81,31 @@ rec { */ mod = base: int: base - (int * (builtins.div base int)); + /* C-style comparisons + + a < b => -1 + a == b => 0 + a > b => 1 + */ + compare = a: b: + if a < b + then -1 + else if a > b + then 1 + else 0; + + /* Split type into two subtypes by predicate `p`, assume + + forall x y . x < y if p x == true && p y == false + + compare elements of the same subtype with `yes` and `no` + comparisons respectively. + */ + splitByAndCompare = p: yes: no: a: b: + if p a + then if p b then yes a b else -1 + else if p b then 1 else no a b; + /* Reads a JSON file. */ importJSON = path: builtins.fromJSON (builtins.readFile path);