-
Notifications
You must be signed in to change notification settings - Fork 25
/
lib.nix
55 lines (46 loc) · 1.54 KB
/
lib.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{ lib
}: rec {
# All fold functions in this module take a record as follows:
# { f :: elem -> elem'
# , empty :: elem'
# , reduce :: elem' -> elem' -> elem'
# , elemLabel :: elem -> label
# , elemChildren :: elem -> [elem]
# }
# foldDAG1 :: Fold -> elem -> elem'
foldDAG1 = fld: root:
let acc = foldDAGRec fld {} [root];
in acc.${fld.elemLabel root};
# foldDAG' :: Fold -> [elem] -> [elem']
foldDAG' = fld: roots:
let acc = foldDAGRec fld {} roots;
in map (elem: acc.${fld.elemLabel elem}) roots;
# foldDAG :: Fold -> [elem] -> { label -> elem' }
foldDAG = fld@{f, empty, elemLabel, reduce, elemChildren}: roots:
(foldDAGRec fld { traversed = {}; elem' = empty;} roots).elem';
# foldDAG' :: Fold -> { label -> elem' } -> [elem] -> { label -> elem' }
foldDAGRec =
fld@{f, empty, elemLabel, reduce, elemChildren}:
acc0:
roots:
let
insert = acc@{traversed, elem'}: elem:
let
label = elemLabel elem;
children = elemChildren elem;
in
if lib.attrsets.hasAttr label traversed
then acc
else
let acc' =
{ elem' = reduce elem' (f elem);
traversed = traversed // { ${label} = null; };
};
in foldDAGRec fld acc' children;
in lib.foldl insert acc0 roots;
withAttr = obj: attrName: def: f:
if builtins.hasAttr attrName obj then f (obj.${attrName}) else def;
optAttr = obj: attrName: def:
if builtins.hasAttr attrName obj then obj.${attrName} else def;
tap = obj: attrName: f: obj // { "${attrName}" = f (obj.${attrName}) ; };
}