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 | 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.
fun | a string or a callable |
parmName | the name of the parameter if fun is a string. Defaults to "a" . |
fun
is a string
, a new single parameter function If fun
is not a string
, an alias 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.
fun | a string or a callable |
parm1Name | the name of the first parameter if fun is a string. Defaults to "a" . |
parm2Name | the name of the second parameter if fun is a string. Defaults to "b" . |
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)
.
pred | A callable |
pred
after reversing the given parametersalias 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)
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)
.
DEPRECATED: Use reverseArgs
pred | A callable |
pred
after reversing the given parametersalias 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
.
pred | A string or a callable |
pred
and returns the logical negation of its return value.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.
fun | A callable |
arg | The first argument to apply to fun
|
fun
with arg
plus the passed parameters.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.
F | the call-able(s) to adjoin |
std.typecons.Tuple
. Each of the elements of the tuple will be the return values of F
. 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], ...
.
fun | the call-able(s) or string (s) to compose into one function |
f(x)
that in turn returns fun[0](fun[1](...(x)))...
. 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.
fun | the call-able(s) or string (s) to compose into one function |
f(x)
that in turn returns fun[0](fun[1](...(x)))...
. // 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
import std.conv : to; string foo(int a) { return to!(string)(a); } int bar(string a) { return to!(int)(a) + 1; } double baz(int a) { return a + 0.5; } writeln(compose!(baz, bar, foo)(1)); // 2.5 writeln(pipe!(foo, bar, baz)(1)); // 2.5 writeln(compose!(baz, `to!(int)(a) + 1`, foo)(1)); // 2.5 writeln(compose!(baz, bar)("1"[])); // 2.5 writeln(compose!(baz, bar)("1")); // 2.5 writeln(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1)); // 2.5
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); }
fun | the call-able to memozie |
maxSize | The maximum size of the GC buffer to hold the return values |
fun
and caches its return values. 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.
F fp
| a function pointer or an aggregate type with opCall defined. |
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 while keeping out
, ref
, and lazy
on the parameters.
args | a parameter list or an std.meta.AliasSeq . |
AliasSeq
of args
with out
, ref
, and lazy
saved.class C { static int foo(int n) { return 1; } static int foo(ref int n) { return 2; } } // with forward int bar()(auto ref int x) { return C.foo(forward!x); } // without forward int baz()(auto ref int x) { return C.foo(x); } int i; writeln(bar(1)); // 1 writeln(bar(i)); // 2 writeln(baz(1)); // 2 writeln(baz(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"
struct X { int i; this(this) { ++i; } } struct Y { private X x_; this()(auto ref X x) { x_ = forward!x; } } struct Z { private const X x_; this()(auto ref X x) { x_ = forward!x; } this()(auto const ref X x) { x_ = forward!x; } } X x; const X cx; auto constX = (){ const X x; return x; }; static assert(__traits(compiles, { Y y = x; })); static assert(__traits(compiles, { Y y = X(); })); static assert(!__traits(compiles, { Y y = cx; })); static assert(!__traits(compiles, { Y y = constX(); })); static assert(__traits(compiles, { Z z = x; })); static assert(__traits(compiles, { Z z = X(); })); static assert(__traits(compiles, { Z z = cx; })); static assert(__traits(compiles, { Z z = constX(); })); Y y1 = x; // ref lvalue, copy writeln(y1.x_.i); // 1 Y y2 = X(); // rvalue, move writeln(y2.x_.i); // 0 Z z1 = x; // ref lvalue, copy writeln(z1.x_.i); // 1 Z z2 = X(); // rvalue, move writeln(z2.x_.i); // 0 Z z3 = cx; // ref const lvalue, copy writeln(z3.x_.i); // 1 Z z4 = constX(); // const rvalue, copy writeln(z4.x_.i); // 1
© 1999–2018 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_functional.html