aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/expressions/builtins.xml13
-rw-r--r--src/libexpr/primops.cc24
-rw-r--r--tests/lang/lib.nix2
3 files changed, 38 insertions, 1 deletions
diff --git a/doc/manual/expressions/builtins.xml b/doc/manual/expressions/builtins.xml
index 6bdfdd55c..0b11e2f5a 100644
--- a/doc/manual/expressions/builtins.xml
+++ b/doc/manual/expressions/builtins.xml
@@ -313,6 +313,19 @@ stdenv.mkDerivation {
</varlistentry>
+ <varlistentry><term><function>builtins.foldl’</function>
+ <replaceable>op</replaceable> <replaceable>nul</replaceable> <replaceable>list</replaceable></term>
+
+ <listitem><para>Reduce a list by applying a binary operator, from
+ left to right, e.g. <literal>foldl’ op nul [x0 x1 x2 ...] = op (op
+ (op nul x0) x1) x2) ...</literal>. The operator is applied
+ strictly, i.e., its arguments are evaluated first. For example,
+ <literal>foldl’ (x: y: x + y) 0 [1 2 3]</literal> evaluates to
+ 6.</para></listitem>
+
+ </varlistentry>
+
+
<varlistentry><term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term>
<listitem><para>Convert a JSON string to a Nix
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index c36a68ce0..6a4b5b042 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1304,6 +1304,29 @@ static void prim_length(EvalState & state, const Pos & pos, Value * * args, Valu
}
+/* Reduce a list by applying a binary operator, from left to
+ right. The operator is applied strictly. */
+static void prim_foldlStrict(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+ state.forceFunction(*args[0], pos);
+ state.forceList(*args[2], pos);
+
+ Value * vCur = args[1];
+
+ if (args[2]->list.length)
+ for (unsigned int n = 0; n < args[2]->list.length; ++n) {
+ Value vTmp;
+ state.callFunction(*args[0], *vCur, vTmp, pos);
+ vCur = n == args[2]->list.length - 1 ? &v : state.allocValue();
+ state.callFunction(vTmp, *args[2]->list.elems[n], *vCur, pos);
+ }
+ else
+ v = *vCur;
+
+ state.forceValue(v);
+}
+
+
/*************************************************************
* Integer arithmetic
*************************************************************/
@@ -1641,6 +1664,7 @@ void EvalState::createBaseEnv()
addPrimOp("__elem", 2, prim_elem);
addPrimOp("__concatLists", 1, prim_concatLists);
addPrimOp("__length", 1, prim_length);
+ addPrimOp("__foldl'", 3, prim_foldlStrict);
// Integer arithmetic
addPrimOp("__add", 2, prim_add);
diff --git a/tests/lang/lib.nix b/tests/lang/lib.nix
index 882005dc1..262cdd7e8 100644
--- a/tests/lang/lib.nix
+++ b/tests/lang/lib.nix
@@ -17,7 +17,7 @@ rec {
then fold (x: y: (flatten x) ++ y) [] x
else [x];
- sum = fold (x: y: add x y) 0;
+ sum = foldl' (x: y: add x y) 0;
hasSuffix = ext: fileName:
let lenFileName = stringLength fileName;