Bug 5510 – std.functional.iterate

Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2011-01-31T03:23:00Z
Last change time
2014-09-14T12:08:45Z
Assigned to
nobody
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2011-01-31T03:23:24Z
I suggest to add to the std.functional module a higher order function similar to this one, that's useful in some situations: /// iterate(f, x, 3) == f(f(f(x))) auto iterate(F, T)(F f, T z, int n) in { assert(n >= 0); } body { foreach (_; 0 .. n) z = f(z); return z; } import std.stdio: writeln; import std.math: sin; void main() { writeln(iterate((double x){return sin(x);}, 0.2, 4)); } Alternative implementation: import std.functional; // iterate(f, x, 3) == f(f(f(x))) auto iterate(alias F, T)(T z, int n) in { assert(n >= 0); } body { alias unaryFun!F fun; foreach (_; 0 .. n) z = fun(z); return z; } import std.stdio: writeln; import std.math: sin; void main() { writeln(iterate!((double x){return sin(x);})(0.2, 4)); writeln(iterate!((x){return sin(x);})(0.2, 4)); writeln(iterate!sin(0.2, 4)); } See also: http://reference.wolfram.com/mathematica/ref/Nest.html http://reference.wolfram.com/mathematica/ref/NestList.html This also suggests: - The alternative name "nest()" for this higher order function; - A second function a nestAll() that returns a lazy iterable of all the intermediate results.
Comment #1 by bearophile_hugs — 2011-02-02T02:25:48Z
Comment #2 by bearophile_hugs — 2014-09-14T12:08:45Z
"iterate" can act like the Haskell iterate, that yields all the intermediate values. This is a basic implementation plus an usage example with the Hailstone sequence: import std.stdio, std.typecons, std.traits, std.typetuple, std.range, std.algorithm; auto iterate(alias F, T)(T x) if (isCallable!F && is(ParameterTypeTuple!F == TypeTuple!T) && is(ReturnType!F == T)) { struct Iterate { T front; enum bool empty = false; void popFront() pure nothrow @safe @nogc { front = F(front); } } return Iterate(x); } // http://en.wikipedia.org/wiki/Collatz_conjecture uint hailstone(uint n) pure nothrow @safe @nogc { if (n == 1) return 1; return (n & 1) ? (n * 3 + 1) : (n / 2); } void main() { enum uint start = 10; start .iterate!hailstone .until(1, OpenRight.no) .writeln; start .recurrence!((a, n) => hailstone(a[n - 1])) .until(1, OpenRight.no) .writeln; } Output: [10, 5, 16, 8, 4, 2, 1] [10, 5, 16, 8, 4, 2, 1] An "iterate" can be implemented with a "recurrence", but iterate looks cleaner for such simple but common cases.