Functions that manipulate other functions.
This module provides functions for compile time function composition. These functions are helpful when constructing predicates for the algorithms in std.algorithm
or std.range
.
Function Name | Description |
---|---|
adjoin | Joins a couple of functions into one that executes the original functions independently and returns a tuple with all the results. |
compose , pipe
| Join a couple of functions into one that executes the original functions one after the other, using one function's result for the next function's argument. |
forward | Forwards function arguments while saving ref-ness. |
lessThan , greaterThan , equalTo
| Ready-made predicate functions to compare two values. |
memoize | Creates a function that caches its result for fast re-evaluation. |
not | Creates a function that negates another. |
partial | Creates a function that binds the first argument of a given function to a given value. |
reverseArgs , binaryReverseArgs
| Predicate that reverses the order of its arguments. |
toDelegate | Converts a callable to a delegate. |
unaryFun , binaryFun
| Create a unary or binary function from a string. Most often used when defining algorithms on ranges. |
Transforms a string representing an expression into a unary function. The string must either use symbol name a
as the parameter or provide the symbol via the parmName
argument. If fun
is not a string, unaryFun
aliases itself away to fun
.
// Strings are compiled into functions: alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1));
Transforms a string representing an expression into a binary function. The string must either use symbol names a
and b
as the parameters or provide the symbols via the parm1Name
and parm2Name
arguments. If fun
is not a string, binaryFun
aliases itself away to fun
.
alias less = binaryFun!("a < b"); assert(less(1, 2) && !less(2, 1)); alias greater = binaryFun!("a > b"); assert(!greater("1", "2") && greater("2", "1"));
Predicate that returns a < b. Correctly compares signed and unsigned integers, ie. -1 < 2U.
assert(lessThan(2, 3)); assert(lessThan(2U, 3U)); assert(lessThan(2, 3.0)); assert(lessThan(-2, 3U)); assert(lessThan(2, 3U)); assert(!lessThan(3U, -2)); assert(!lessThan(3U, 2)); assert(!lessThan(0, 0)); assert(!lessThan(0U, 0)); assert(!lessThan(0, 0U));
Predicate that returns a > b. Correctly compares signed and unsigned integers, ie. 2U > -1.
assert(!greaterThan(2, 3)); assert(!greaterThan(2U, 3U)); assert(!greaterThan(2, 3.0)); assert(!greaterThan(-2, 3U)); assert(!greaterThan(2, 3U)); assert(greaterThan(3U, -2)); assert(greaterThan(3U, 2)); assert(!greaterThan(0, 0)); assert(!greaterThan(0U, 0)); assert(!greaterThan(0, 0U));
Predicate that returns a == b. Correctly compares signed and unsigned integers, ie. !(-1 == ~0U).
assert(equalTo(0U, 0)); assert(equalTo(0, 0U)); assert(!equalTo(-1, ~0U));
N-ary predicate that reverses the order of arguments, e.g., given pred(a, b, c)
, returns pred(c, b, a)
.
alias gt = reverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = reverseArgs!(foo); writeln(zyx(5, 4)); // foo(4, 5)
int abc(int a, int b, int c) { return a * b + c; } alias cba = reverseArgs!abc; writeln(abc(91, 17, 32)); // cba(32, 17, 91)
int a(int a) { return a * 2; } alias _a = reverseArgs!a; writeln(a(2)); // _a(2)
int b() { return 4; } alias _b = reverseArgs!b; writeln(b()); // _b()
Binary predicate that reverses the order of arguments, e.g., given pred(a, b)
, returns pred(b, a)
.
alias gt = binaryReverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1));
int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = binaryReverseArgs!(foo); writeln(zyx(5, 4)); // foo(4, 5)
Negates predicate pred
.
import std.algorithm.searching : find; import std.functional; import std.uni : isWhite; string a = " Hello, world!"; writeln(find!(not!isWhite)(a)); // "Hello, world!"
Partially applies fun by tying its first argument to arg.
int fun(int a, int b) { return a + b; } alias fun5 = partial!(fun, 5); writeln(fun5(6)); // 11 // Note that in most cases you'd use an alias instead of a value // assignment. Using an alias allows you to partially evaluate template // functions without committing to a particular type of the function.
Takes multiple functions and adjoins them together. The result is a std.typecons.Tuple
with one element per passed-in function. Upon invocation, the returned tuple is the adjoined results of all functions.
F.length == 1
), adjoin
simply aliases to the single passed function (F[0]
).import std.functional, std.typecons : Tuple; static bool f1(int a) { return a != 0; } static int f2(int a) { return a / 2; } auto x = adjoin!(f1, f2)(5); assert(is(typeof(x) == Tuple!(bool, int))); assert(x[0] == true && x[1] == 2);
Composes passed-in functions fun[0], fun[1], ...
returning a function f(x)
that in turn returns fun[0](fun[1](...(x)))...
. Each function can be a regular functions, a delegate, or a string.
pipe
import std.algorithm.comparison : equal; import std.algorithm.iteration : map; import std.array : split; import std.conv : to; // First split a string in whitespace-separated tokens and then // convert each token into an integer assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3]));
Pipes functions in sequence. Offers the same functionality as compose
, but with functions specified in reverse order. This may lead to more readable code in some situation because the order of execution is the same as lexical order.
// Read an entire text file, split the resulting string in // whitespace-separated tokens, and then convert each token into an // integer int[] a = pipe!(readText, split, map!(to!(int)))("file.txt");
compose
Memoizes a function so as to avoid repeated computation. The memoization structure is a hash table keyed by a tuple of the function's arguments. There is a speed gain if the function is repeatedly called with the same arguments and is more expensive than a hash table lookup. For more information on memoization, refer to this book chapter.
double transmogrify(int a, string b) { ... expensive computation ... } alias fastTransmogrify = memoize!transmogrify; unittest { auto slow = transmogrify(2, "hello"); auto fast = fastTransmogrify(2, "hello"); assert(slow == fast); }Technically the memoized function should be pure because
memoize
assumes it will always return the same result for a given tuple of arguments. However, memoize
does not enforce that because sometimes it is useful to memoize
an impure function, too. ulong fib(ulong n) @safe { return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); } writeln(fib(10)); // 55
ulong fact(ulong n) @safe { return n < 2 ? 1 : n * memoize!fact(n - 1); } writeln(fact(10)); // 3628800
fact
up to the largest argument. To only cache the final result, move memoize
outside the function as shown below. ulong factImpl(ulong n) @safe { return n < 2 ? 1 : n * factImpl(n - 1); } alias fact = memoize!factImpl; writeln(fact(10)); // 3628800
maxSize
parameter is specified, memoize
will used a fixed size hash table to limit the number of cached entries. ulong fact(ulong n) { // Memoize no more than 8 values return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); } writeln(fact(8)); // 40320 // using more entries than maxSize will overwrite existing entries writeln(fact(10)); // 3628800
Convert a callable to a delegate with the same parameter list and return type, avoiding heap allocations and use of auxiliary storage.
void doStuff() { writeln("Hello, world."); } void runDelegate(void delegate() myDelegate) { myDelegate(); } auto delegateToPass = toDelegate(&doStuff); runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world."
@safe
functions.static int inc(ref uint num) { num++; return 8675309; } uint myNum = 0; auto incMyNumDel = toDelegate(&inc); auto returnVal = incMyNumDel(myNum); writeln(myNum); // 1
Forwards function arguments with saving ref-ness.
class C { static int foo(int n) { return 1; } static int foo(ref int n) { return 2; } } int bar()(auto ref int x) { return C.foo(forward!x); } writeln(bar(1)); // 1 int i; writeln(bar(i)); // 2
void foo(int n, ref string s) { s = null; foreach (i; 0 .. n) s ~= "Hello"; } // forwards all arguments which are bound to parameter tuple void bar(Args...)(auto ref Args args) { return foo(forward!args); } // forwards all arguments with swapping order void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } string s; bar(1, s); writeln(s); // "Hello" baz(s, 2); writeln(s); // "HelloHello"
© 1999–2017 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_functional.html