* Moved mapAttrs to attrsets.nix.

* Added a function mapAttrsRecursive, which is like mapAttrs, but
  recursively applies itself to attribute sets.
* Commented and cleaned up some functions.

svn path=/nixpkgs/trunk/; revision=14495
This commit is contained in:
Eelco Dolstra 2009-03-10 15:18:38 +00:00
parent e629ce0e07
commit b53ef57554
2 changed files with 84 additions and 22 deletions

View file

@ -3,16 +3,18 @@
with {
inherit (builtins) head tail;
inherit (import ./default.nix) fold;
inherit (import ./strings.nix) concatStringsSep;
};
rec {
inherit (builtins) attrNames listToAttrs hasAttr isAttrs;
# Return an attribute from nested attribute sets. For instance ["x"
# "y"] applied to some set e returns e.x.y, if it exists. The
# default value is returned otherwise. !!! there is also
# builtins.getAttr (is there a better name for this function?)
/* Return an attribute from nested attribute sets. For instance
["x" "y"] applied to some set e returns e.x.y, if it exists. The
default value is returned otherwise. !!! there is also
builtins.getAttr (is there a better name for this function?)
*/
getAttr = attrPath: default: e:
let attr = head attrPath;
in
@ -21,14 +23,80 @@ rec {
then getAttr (tail attrPath) default (builtins.getAttr attr e)
else default;
# ordered by name
attrValues = attrs: attrVals (__attrNames attrs) attrs;
attrVals = nameList : attrSet :
map (x: builtins.getAttr x attrSet) nameList;
getAttrFromPath = attrPath: set:
let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
in getAttr attrPath (abort errorMsg) set;
# iterates over a list of attributes collecting the attribute attr if it exists
catAttrs = attr : l : fold ( s : l : if (hasAttr attr s) then [(builtins.getAttr attr s)] ++ l else l) [] l;
/* Return the specified attributes from a set.
Example:
attrVals ["a" "b" "c"] as
=> [as.a as.b as.c]
*/
attrVals = nameList: set:
map (x: builtins.getAttr x set) nameList;
}
/* Return the values of all attributes in the given set, sorted by
attribute name.
Example:
attrValues {c = 3; a = 1; b = 2;}
=> [1 2 3]
*/
attrValues = attrs: attrVals (attrNames attrs) attrs;
/* Collect each attribute named `attr' from a list of attribute
sets. Sets that don't contain the named attribute are ignored.
Example:
catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
=> [1 2]
*/
catAttrs = attr: l: fold (s: l: if hasAttr attr s then [(builtins.getAttr attr s)] ++ l else l) [] l;
/* Utility function that creates a {name, value} pair as expected by
builtins.listToAttrs. */
nameValuePair = name: value: { inherit name value; };
/* Apply a function to each element in an attribute set. The
function takes two arguments --- the attribute name and its value
--- and returns the new value for the attribute. The result is a
new attribute set.
Example:
mapAttrs (name: value: name + "-" + value)
{x = "foo"; y = "bar";}
=> {x = "x-foo"; y = "y-bar";}
*/
mapAttrs = f: set:
listToAttrs (map (attr: nameValuePair attr (f attr (builtins.getAttr attr set))) (attrNames set));
/* Like `mapAttrs', except that it recursively applies itself to
values that attribute sets. Also, the first argument is a *list*
of the names of the containing attributes.
Example:
mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
{ n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
=> { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
*/
mapAttrsRecursive =
let
recurse = path: f: set:
let
g =
name: value:
if isAttrs value
then recurse (path ++ [name]) f value
else f (path ++ [name]) value;
in mapAttrs g set;
in recurse [];
}

View file

@ -236,14 +236,8 @@ rec {
# should be renamed to mapAttrsFlatten
mapRecordFlatten = f : r : map (attr: f attr (builtins.getAttr attr r) ) (attrNames r);
# maps a function on each attr value
# f = attr : value : ..
mapAttrs = f : r : listToAttrs ( mapRecordFlatten (a : v : nv a ( f a v ) ) r);
# to be used with listToAttrs (_a_ttribute _v_alue)
nv = name : value : { inherit name value; };
# attribute set containing one attribute
nvs = name : value : listToAttrs [ (nv name value) ];
nvs = name : value : listToAttrs [ (nameValuePair name value) ];
# adds / replaces an attribute of an attribute set
setAttr = set : name : v : set // (nvs name v);
@ -322,8 +316,8 @@ rec {
mergeAttrsByFuncDefaults = foldl mergeAttrByFunc { inherit mergeAttrBy; };
# sane defaults (same name as attr name so that inherit can be used)
mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; }
listToAttrs (map (n : nv n lib.concat) [ "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" ])
// listToAttrs (map (n : nv n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]);
listToAttrs (map (n : nameValuePair n lib.concat) [ "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" ])
// listToAttrs (map (n : nameValuePair n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]);
# returns atribute values as a list
flattenAttrs = set : map ( attr : builtins.getAttr attr set) (attrNames set);
@ -332,7 +326,7 @@ rec {
# pick attrs subset_attr_names and apply f
subsetmap = f : attrs : subset_attr_names :
listToAttrs (fold ( attr : r : if __hasAttr attr attrs
then r ++ [ ( nv attr ( f (__getAttr attr attrs) ) ) ] else r ) []
then r ++ [ ( nameValuePair attr ( f (__getAttr attr attrs) ) ) ] else r ) []
subset_attr_names );
# prepareDerivationArgs tries to make writing configurable derivations easier
@ -372,7 +366,7 @@ rec {
prepareDerivationArgs = args:
let args2 = { cfg = {}; flags = {}; } // args;
flagName = name : "${name}Support";
cfgWithDefaults = (listToAttrs (map (n : nv (flagName n) false) (attrNames args2.flags)))
cfgWithDefaults = (listToAttrs (map (n : nameValuePair (flagName n) false) (attrNames args2.flags)))
// args2.cfg;
opts = flattenAttrs (mapAttrs (a : v :
let v2 = if (v ? set || v ? unset) then v else { set = v; };