Implementation
Here are my versions. I will start with FoldWhile
:
Clear[dressInCtr];
dressInCtr[test_, max_] :=
Module[{ctr = 0}, (++ctr <= max ) && test[##] &]
Clear[FoldWhile];
FoldWhile[f_, test_, start_, secargs_List, max_Integer] :=
FoldWhile[f, dressInCtr[test, max], start, secargs];
FoldWhile[f_, test_, start_, secargs_List] :=
Module[{last = start},
Fold[
If[test[##], last = f[##], Return[last, Fold]] &,
start,
secargs]];
The FoldWhileList
is a bit more involved:
Clear[FoldWhileList];
FoldWhileList[f_, test_, start_, secargs_List, max_Integer] :=
FoldWhileList[f, dressInCtr[test, max], start, secargs];
FoldWhileList[f_, test_, start_, secargs_List] :=
Module[{tag},
If[# === {}, {start}, Prepend[First@#, start]] &@
Reap[
Fold[
If[test[##], Sow[f[##],tag], Return[Null, Fold]] &,
start,
secargs],
_, #2 &][[2]]]
Examples
Here are some examples:
FoldWhileList[Plus,#2<5&,0,Range[30]]
(* {0,1,3,6,10} *)
FoldWhileList[Plus,#2<5&,0,Range[30],3]
(* {0,1,3,6} *)
FoldWhile[Plus,#2<5&,0,Range[30]]
(* 10 *)
FoldWhile[Plus,#2<5&,0,Range[30],3]
(* 6 *)
Remarks
I chose to use Fold
itself as an economical way to implement FoldWhile
and FoldWhileList
. It helped that the two-argument version of Return
(undocumented) could be used here. I also found it simplest to implement the extended form with a fifth parameter giving maximal number of iterations, by dressing the test criteria in a closure, which is done via a closure generator function dressInCtr
. This also seems to be a good illustration of the usefulness of closures.
m
most recent results. I this is really necessary, then your implementation is likely a way to go, sinceFold
can not be used to implement this. As to the complexity - I don't think most users have to reimplement it themselves - they could as well come to this page and pick whichever implementation they like the most :). $\endgroup$