std.functional
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. |
curry | Converts a multi-argument function into a series of single-argument functions. f(x, y) == curry(f)(x)(y) |
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. |
- License:
- Boost License 1.0.
- Authors:
- Andrei Alexandrescu
- Source
- std/functional.d
- template unaryFun(alias fun, string parmName = "a")
-
Transforms a
string
representing an expression into a unary function. Thestring
must either use symbol namea
as the parameter or provide the symbol via theparmName
argument.- Parameters:
fun a string
or a callableparmName the name of the parameter if fun
is a string. Defaults to"a"
.
- Returns:
- If
fun
is astring
, a new single parameter function Iffun
is not astring
, an alias tofun
.
- Examples:
-
// Strings are compiled into functions: alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1));
- template binaryFun(alias fun, string parm1Name = "a", string parm2Name = "b")
-
Transforms a
string
representing an expression into a binary function. Thestring
must either use symbol namesa
andb
as the parameters or provide the symbols via theparm1Name
andparm2Name
arguments.- Parameters:
fun a string
or a callableparm1Name 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"
.
- Returns:
- If
fun
is not a string,binaryFun
aliases itself away tofun
.
- Examples:
-
alias less = binaryFun!("a < b"); assert(less(1, 2) && !less(2, 1)); alias greater = binaryFun!("a > b"); assert(!greater("1", "2") && greater("2", "1"));
- alias lessThan = safeOp!"<".safeOp(T0, T1)(auto ref T0 a, auto ref T1 b);
-
Predicate that returns a < b. Correctly compares signed and unsigned integers, ie. -1 < 2U.
- Examples:
-
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));
- alias greaterThan = safeOp!">".safeOp(T0, T1)(auto ref T0 a, auto ref T1 b);
-
Predicate that returns a > b. Correctly compares signed and unsigned integers, ie. 2U > -1.
- Examples:
-
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));
- alias equalTo = safeOp!"==".safeOp(T0, T1)(auto ref T0 a, auto ref T1 b);
-
Predicate that returns a == b. Correctly compares signed and unsigned integers, ie. !(-1 == ~0U).
- Examples:
-
assert(equalTo(0U, 0)); assert(equalTo(0, 0U)); assert(!equalTo(-1, ~0U));
- template reverseArgs(alias pred)
-
N-ary predicate that reverses the order of arguments, e.g., given
pred(a, b, c)
, returnspred(c, b, a)
.- Parameters:
pred A callable
- Returns:
- A function which calls
pred
after reversing the given parameters
- Examples:
-
alias gt = reverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1));
- Examples:
-
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)
- Examples:
-
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)
- Examples:
-
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)
- Examples:
-
int a(int a) { return a * 2; } alias _a = reverseArgs!a; writeln(a(2)); // _a(2)
- Examples:
-
int b() { return 4; } alias _b = reverseArgs!b; writeln(b()); // _b()
- template not(alias pred)
-
Negates predicate
pred
.- Parameters:
pred A string or a callable
- Returns:
- A function which calls
pred
and returns the logical negation of its return value.
- Examples:
-
import std.algorithm.searching : find; import std.functional; import std.uni : isWhite; string a = " Hello, world!"; writeln(find!(not!isWhite)(a)); // "Hello, world!"
- template partial(alias fun, alias arg)
-
Partially applies fun by tying its first argument to arg.
- Parameters:
fun A callable arg The first argument to apply to fun
- Returns:
- A new function which calls
fun
witharg
plus the passed parameters.
- Examples:
-
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.
- auto curry(alias F)()
Constraints: if (isCallable!F && Parameters!F.length);
auto curry(T)(T t)
Constraints: if (isCallable!T && Parameters!T.length); -
Takes a function of (potentially) many arguments, and returns a function taking one argument and returns a callable taking the rest. f(x, y) == curry(f)(x)(y)
- Parameters:
F a function taking at least one argument T t
a callable object whose opCall takes at least 1 object
- Returns:
- A single parameter callable object
- Examples:
-
int f(int x, int y, int z) { return x + y + z; } auto cf = curry!f; auto cf1 = cf(1); auto cf2 = cf(2); writeln(cf1(2)(3)); // f(1, 2, 3) writeln(cf2(2)(3)); // f(2, 2, 3)
- Examples:
-
//works with callable structs too struct S { int w; int opCall(int x, int y, int z) { return w + x + y + z; } } S s; s.w = 5; auto cs = curry(s); auto cs1 = cs(1); auto cs2 = cs(2); writeln(cs1(2)(3)); // s(1, 2, 3) writeln(cs1(2)(3)); // (1 + 2 + 3 + 5) writeln(cs2(2)(3)); // s(2, 2, 3)
- template adjoin(F...) if (F.length == 1)
template adjoin(F...) if (F.length > 1) -
Takes multiple functions and adjoins them together.
- Parameters:
F the call-able(s) to adjoin
- Returns:
- A new function which returns a
std.typecons.Tuple
. Each of the elements of the tuple will be the return values ofF
.
- Note
- In the special case where only a single function is provided (
F.length == 1
), adjoin simply aliases to the single passed function (F[0]
).
- Examples:
-
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);
- template compose(fun...) if (fun.length > 0)
-
Composes passed-in functions
fun[0], fun[1], ...
.- Parameters:
fun the call-able(s) or string
(s) to compose into one function
- Returns:
- A new function
f(x)
that in turn returnsfun[0](fun[1](...(x)))...
.
- See Also:
pipe
- Examples:
-
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]));
- template pipe(fun...)
-
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.- Parameters:
fun the call-able(s) or string
(s) to compose into one function
- Returns:
- A new function
f(x)
that in turn returnsfun[$-1](...fun[1](fun[0](x)))...
.
- Example
// 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");
- See Also:
compose
- Examples:
-
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
- ReturnType!fun memoize(alias fun)(Parameters!fun args);
ReturnType!fun memoize(alias fun, uint maxSize)(Parameters!fun args); -
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.
- Example
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); }
- Parameters:
fun the call-able to memozie maxSize The maximum size of the GC buffer to hold the return values
- Returns:
- A new function which calls
fun
and caches its return values.
- Note
- 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.
- Examples:
- To memoize a recursive function, simply insert the memoized call in lieu of the plain recursive call. For example, to transform the exponential-time Fibonacci implementation into a linear-time computation:
ulong fib(ulong n) @safe nothrow { return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); } writeln(fib(10)); // 55
- Examples:
- To improve the speed of the factorial function,
ulong fact(ulong n) @safe { return n < 2 ? 1 : n * memoize!fact(n - 1); } writeln(fact(10)); // 3628800
- Examples:
- This memoizes all values of
fact
up to the largest argument. To only cache the final result, movememoize
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
- Examples:
- When the
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
- auto toDelegate(F)(auto ref F fp)
Constraints: if (isCallable!F); -
Convert a callable to a delegate with the same parameter list and return type, avoiding heap allocations and use of auxiliary storage.
- Parameters:
F fp
a function pointer or an aggregate type with opCall
defined.
- Returns:
- A delegate with the context pointer pointing to nothing.
- Example
void doStuff() { writeln("Hello, world."); } void runDelegate(void delegate() myDelegate) { myDelegate(); } auto delegateToPass = toDelegate(&doStuff); runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world."
- Bugs:
- Does not work with
@safe
functions. - Ignores C-style / D-style variadic arguments.
- Does not work with
- Examples:
-
static int inc(ref uint num) { num++; return 8675309; } uint myNum = 0; auto incMyNumDel = toDelegate(&inc); auto returnVal = incMyNumDel(myNum); writeln(myNum); // 1
- template forward(args...)
-
Forwards function arguments while keeping
out
,ref
, andlazy
on the parameters.- Parameters:
args a parameter list or an std.meta.AliasSeq
.
- Returns:
- An
AliasSeq
ofargs
without
,ref
, andlazy
saved.
- Examples:
-
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
- Examples:
-
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"
- Examples:
-
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–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_functional.html