From 5ae1d3fd7b363b6aab71b94626055ea91675f90d Mon Sep 17 00:00:00 2001 From: sterni Date: Thu, 4 Mar 2021 22:20:09 +0100 Subject: feat(users/sterni/nix/flow): add switch conditional switch would probably otherwise be called match, but has been renamed so it isn't confused with string.match and the enum matching capabilities yants has. It implements the closest to pattern matching nix can come which is still flexible enough to not be painful: Syntactically it works like cond, but is given a value. Instead of booleans it checks passed predicates or equality if simple values are passed. Both types of checks can be mixed. Change-Id: I40f000979cfd469316e15fd58d6c3a80312c1cc4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2589 Tested-by: BuildkiteCI Reviewed-by: sterni --- users/sterni/nix/flow/default.nix | 76 +++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/users/sterni/nix/flow/default.nix b/users/sterni/nix/flow/default.nix index a9fe3c6735..b5783bd86d 100644 --- a/users/sterni/nix/flow/default.nix +++ b/users/sterni/nix/flow/default.nix @@ -6,47 +6,77 @@ let yants ; + inherit (depot.users.sterni.nix) + fun + ; + # we must avoid evaluating any of the sublists # as they may contain conditions that throw condition = yants.restrict "condition" (ls: builtins.length ls == 2) (yants.list yants.any); - /* cond :: [ [ bool any ] ] -> any - * - * Like the common lisp macro: takes a list - * of two elemented lists whose first element - * is a boolean. The second element of the - * first list that has true as its first - * element is returned. - * - * Example: - * - * cond [ - * [ (builtins.isString true) 12 ] - * [ (3 == 2) 13 ] - * [ true 42 ] - * ] - * - * => 42 + /* Like the common lisp macro: takes a list + of two elemented lists whose first element + is a boolean. The second element of the + first list that has true as its first + element is returned. + + Type: [ [ bool a ] ] -> a + + Example: + + cond [ + [ (builtins.isString true) 12 ] + [ (3 == 2) 13 ] + [ true 42 ] + ] + + => 42 */ - cond = conds: + cond = conds: switch true conds; + + /* Generic pattern match-ish construct for nix. + Takes a bunch of lists which are of length + two and checks the first element for either + a predicate or a value. The second value of + the first list which either has a value equal + to or a function that evaluates to true for + the given value. + + Type: a -> [ [ (function | a) b ] ] -> b + + Example: + + switch "foo" [ + [ "smol" "SMOL!!!" ] + [ (x: builtins.stringLength x <= 3) "smol-ish" ] + [ (fun.const true) "not smol" ] + ] + + => "smol-ish" + */ + switch = x: conds: if builtins.length conds == 0 - then builtins.throw "cond: exhausted all conditions" + then builtins.throw "exhausted all conditions" else let c = condition (builtins.head conds); + s = builtins.head c; + b = + if builtins.isFunction s + then s x + else x == s; in - if builtins.head c + if b then builtins.elemAt c 1 - else cond (builtins.tail conds); + else switch x (builtins.tail conds); - # TODO(sterni): condf or magic - # like in { inherit cond + switch ; } -- cgit 1.4.1