dranges.functional

This module contains all the function-related templates. Its main use used to be to generate functions from strings, with the naryFun template, an extension of std. functional .unaryFun and binaryFun. Now, it presents a nice collection of adaptors and transformers: functions or templates acting on functions to transform them.

License:
Boost License 1.0.

Authors:
Philippe Sigaud

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

template arity (alias fun) if (isFunction!(fun))
Gives the arity of a function: unary, binary, etc. A 0-args function has an arity of 0.

int foo0() { return 0;}
int foo1(int a) { return a;}
int foo2(int a, int b) { return a+b;}

assert(arity!foo0 == 0);
assert(arity!foo1 == 1);
assert(arity!foo2 == 2);
It does not work on non-instantiated template functions (because they are not functions) and gives an arity of 1 for variadic functions, because their variadic list is considered as one arg.
T foo(T)(T t) { ...};
auto a = arity!foo; // error !
auto b = arity!(foo!int); // OK.
//
int foov(int a...) { return 0;}
assert(arity!foov == 1);


See Also:
dranges.templates.TemplateFunArity.

template ReturnTypes (Funs...)
Given a bunch of functions names, gives the typetuple of their return types. Used by juxtapose.

template ParameterTypeTuples (alias fun,Rest...)
Given a bunch of functions names, gives the (flattened) typetuple of their return values. Used by juxtapose.

Tuple!(StaticFilter!(isNotVoid,ReturnTypes!(Funs))) juxtapose (Funs...)(ParameterTypeTuples!(Funs) params);
Takes n functions and create a new one, taking as arguments the concatenation of all input functions arguments and returning a tuple of their results. It will deal correctly with nullary (0-arg) functions by inserting their return value at the right place and with void-returning functions. Do not use variadic functions, though.

This template is very useful when dealing with tuple-returning ranges.

Example:
int foo(int i) { return i*i;}       // int -> int
int bar() { return 0;}              // ()  -> int
void baz(string s) {}               // string -> ()
double[] quux(double d, double[] f) // (double,double[]) -> double[]
    { return f ~ d;}

alias juxtapose!(foo,bar,baz,quux) jux; // jux takes (int,string, double, double[]), returns Tuple!(int,int,double[]);

auto ir = [0,1,2,3,4,5];
auto sr = ["abc", "def","ghijk"];
auto dr = [3.14,2.78,1.00,-1.414];
auto fr = [[0.1,0.2], [0.0,-1.0,-2.0]];

auto m = tmap!jux(ir,sr,dr,fr);


Note:
another, more mathematical way, to look at it is that juxtapose creates a function whose type is the product the input functions' types. In D, product of types are tuples.

FlipnR!(fun) flipn (alias fun)(size_t n);
Flip and curry range functions, like take, drop, etc. These take a range and a size_t arguments, like take(r,3), etc. But sometimes, you just want to create a curried function that will act on any range.

Example:
alias flipn!take takeN; // takeN is a generic function, waiting for a number of elements to take.
auto take3 = takeN(3);  // take3 is a generic function, taking 3 elements on any range (returns take(range,3))

auto threes = map!take3([[0,1,2,3,4,5],[6,7,8,9], [10]]); // get the first three elements of each range
auto witness =          [[0,1,2],      [6,7,8],   [10]];
foreach(i, elem; witness)  {assert(equal(elem, threes.front)); threes.popFront;}


template flip (alias fun)
Flips (reverses) the arguments of a function. It also works for template functions, even variadic ones. Do not use it on standard variadic functions, though.

Example:
int sub(int i, int j) { return i-j;}
int one(int i) { return i;}
double three(double a, int b, string c) { return a;}

alias flip!sub fsub;
alias flip!one fone;
alias flip!three fthree;

assert(fsub(1,2) == sub(2,1));
assert(fone(1) == one(1));
assert(fthree("abc", 0, 3.14) == three(3.14, 0, "abc"));

string conj(A,B)(A a, B b)
{
    return to!string(a)~to!string(b);
}

string conjAll(A...)(A a) // variadic template function
{
    string result;
    foreach(i,elem;a) result ~= to!string(elem);
    return result;
}

alias flip!conj fconj;
alias flip!conjAll fconjAll;

assert(fconj(1,2) == "21");
assert(fconjAll(1,2,3,4) == "4321");


template curry (alias fun)
Takes a D function, and curries it (in the Haskell sense, not as Phobos' std.functional.curry): given a n-args function, it creates n 1-arg functions nested inside one another. When all original arguments are reached, it returns the result. It's useful to make 'incomplete' functions to be completed by ranges elements.

Example:
int add(int i, int j) { return i+j;}
alias curry!add cadd; // cadd waits for an int, will return an int delegate(int)
auto add3 = cadd(3); // add3 is a function that take an int and return this int + 3.

auto m = map!add3([0,1,2,3]);
assert(equal(m, [3,4,5,6]));

bool equals(int i, int j) { return i==j;}
alias curry!equals cequals;
auto equals4 = cequals(4); // equals4 is a function taking an int and return true iff this int is 4.
auto f = filter!equals4([2,3,4,5,4,3,2,2,3,4]);
assert(equal(f, [4,4,4]));
What's fun is that it'll work for template functions too.

Example:
string conj(A, B)(A a, B b)
{
    return to!string(a)~to!string(b);
}

alias curry!conj cconj;
auto c1 = cconj(1); // c1 is a template function waiting for any type.
assert(c1('a') == "1a");


BUG:
for now, it does not verify the compatibility of types while you give it the arguments. It's only at the end that it sees whether or not it can call the function with these arguments.

Example:
// given a function like this, with dependencies between the arguments' types:
A foo(A,B,C)(A a, Tuple!(B,A) b, Tuple!(C,B,A) c) { return a+b.field[1]+c.field[2];}
// if you curries it and gives it an int as first argument, the returned template function should really be:
int foo2(B,C)(Tuple!(B,int) b) { return anotherFunction;}
// because we now know A to be an int...


InvertibleFun!(A,B) invertibleFun (A, B)(B delegate(A) fun, A delegate(B) funInv);
Takes two delegates: one from A to B, the other from B to A. A and B must be different types. The functions are supposed to be the inverse of one another (that is: f(g(x)) == x), but that's not checked. invertibleFun is then a function that accepts either a A or a B and then returns a B or a A.

Apply!(T) apply (T...)(T value);
Takes a value argument and creates a function (in fact, a struct with an opCall) that will accept any delegate and apply it to the original value. It's useful when you want to map a certain value on a range of functions: just map apply!value to the range.

Example:
int f0(int i) { return i;}
int f1(int i) { return i*i;}
int f2(int i) { return i*i*i;}

auto apply4 = apply(4); // will call any function with '4' as argument.
auto rangeFun = [&f0, &f1, &f2];
auto map4 = map!apply4(rangeFun);
assert(equal(map4, [4, 4*4, 4*4*4]));

// This works for n-args functions too:
double g0(int i, double d) { return i+d;}

auto apply123 = apply(1, 2.30);
assert(apply123(&g0) == 3.30);


template destructured (alias fun)
Transforms a standard function into a destructuring one. Given:
int foo(int a, int b, int c) {}
then, destructured!foo is a function that accepts three ints as arguments, but also Tuple!(int,int,int) or int[] or int[3] or even any class C or struct S if C.tupleof/S.tupleof gives three ints. In effect, destructured!foo will try to destructure (decompose, crack open, if you will) anything passed to it, to find three ints in a row to give to foo.

Note:
It's still 'in construction', as it depends on the _() function from dranges.reftuple. The doc should be extended.

TODO:
also if t is itself a tuple _(params) = t;

template mapper (alias fun)
Transforms a function foo taking a T into a function accepting a T[] as an argument and which applies foo to each element of the array, returning the resulting array.

Example:
int foo(int i) { return i*i;}
alias mapper!foo mfoo;

assert(mfoo([0,1,2,3,4]) == [0,1,4,9,16]);
If foo takes more than one argument, mapper!foo waits for a Tuple!(Args)[] or accepts a variadic number of arguments, as long as the types and their numbers correspond.

Example:
int bar(int i, double j, string s) { return (to!int(i*j));}
alias mapper!bar mbar;

assert(mbar(1,3.14,"ab", 2,-0.5,"hello!", 0,0,"") == [3,-3,0]);


TODO:
expand tuples [tuple(a,b), tuple(a,b), ...]

template tupler (alias fun)
Transforms a function foo accepting a T into a function accepting a Tuple!(T,T,T,...T) (or any tuple with compatible types). It will apply foo to all elements of the tuple and return the tuple of these results.

Example:
int foo(int i) { return i*i;}
alias tupler!foo tfoo;
auto t = tuple(0,1,2,3,4);

assert(tfoo(t) == tuple(0,1,4,9,16));


void voidFun (...);
The void function: takes any arguments, returns void.

void nullFun ();
The null function: takes no argument, returns void.

T[0] delegate(...) constantFun (T...)(T t);
Tuple!(T) delegate(...) constantFun (T...)(T t);
void delegate(...) constantFun (T...)(T t);
Takes any value, returns a constant function: one that accepts any arguments and will always return the initial value. If called with no argument, it will produce the equivalent of voidFun.

Example:
auto one = constantFun(1);
assert(equal(map!one(["a","b","abc"]), [1,1,1]));


template extendFun (alias fun)
Takes a function foo and 'extends' it, allowing it to accept any type of argument. If the arguments types are compatible with foo, returns foo(args) otherwise, it just returns the argument.

That may seem a strange template to define, but it's quite useful for mapping a tuple (see dranges.tuple.mapTuple and dranges.tupletree.mapTree). Suppose you have a tuple and want to change only the strings in it. Define foo to act on strings, extend it with extendFun!foo and voila, you can then map extendFun!foo on your tuple: the strings will be transformed, leaving the other types untouched. I learnt the trick from a Haskell article.

Example:
import dranges.tuple;

auto t = tuple("bin", 1024, 3.14159,
               "src", 0,    1.0,
               "myDirectory/foo", 100, -2.3);

string foo(string s) { return "std/" ~ s;}

auto efoo = extendFun!foo; // beware: it's not alias extendFun!foo efoo;, as for other templates around here.

auto t2 = mapTuple ! efoo (t);

assert(t2 == tuple("std/bin", 1024, 3.14159,
                   "std/src", 0,    1.0,
                   "std/myDirectory/foo", 100, -2.3));


ExtendFun0!(fun,D) extendFun0 (alias fun, D)(D defaultValue);
Same as before, but with a default value returned when extendFun is offered an arg that foo cannot accept. The default value can be of any type.

Example:
import dranges.tuple;

auto t = tuple("bin", 1024, 3.14159,
               "src", 0,    1.0,
               "myDirectory/foo", 100, -2.3);

string foo(string s) { return "std/" ~ s;}

auto efoo = extendFun0!foo(0);

auto t2 = mapTuple ! efoo (t);

assert(t2 == tuple("std/bin",               0, 0,
                   "std/src",               0, 0,
                   "std/myDirectory/foo",   0, 0));


template eitherFun (F...)
This is just a wrapper around the match function found in dranges.patternmatch, here to emphasize the way match is just a many-types-to-many-types 'function'. Explained a bit more clearly, eitherFun takes any number of functions and keep them near its hot little heart. When passed an argument, it will successively test each function and returns the result of the first one that matches. No match means it will throw a NoMatch exception. Functions are tested the same order they were passed as arguments.

How is this different from overloading, will you ask? I'm glad you did:

  • first, you can use it to 'group' many different functions, from different origins and different names.
  • second (and that may be the most important point), it's a template, so the return type of eitherFun can be different for each argument type. So you can use it to map a range, but also a tuple, with dranges.tuple.mapTuple.
  • third, it accepts template functions. In fact, it even accepts 'string' functions, as in "a+b*c-d.expand". See the patternmatch module documentation for more explanations.
  • fourth, once it's defined, you can pass it around as one entity. Most notably, it can becomes the argument of another meta-function there or even the argument to another eitherFun!


So, in functional languages terms, it's a sum of functions (just as juxtapose is a product).

Example:
int    f1(int i) { return i;}
double f2(double d) { return d*d;}
int    f3(int i, string s) { return i;}
string f4(string s, int i) { return s;}

alias eitherFun!(f1,f2,f3,f4) efun; // efun accepts either an int, or a double, or a (int,string) or a (string, int)

assert(efun(1) == 1);
assert(efun(1.5) == 2.25);
assert(efun(1,"abc") == 1);
assert(efun("abc",1) == "abc");

// Let's extend it, then.
int[] f5(int[] i) { return i.reverse;}

alias eitherFun!(efun, f5) efun5;   // efun5 will test f1, then f2, ... and f5 at last resort.
// alias eitherFun(f5, efun) efun5bis would have tested f5 first, then f1, ...

assert(efun5(1) == 1);              // efun5 is like efun
assert(efun5(1.5) == 2.25);
assert(efun5(1,"abc") == 1);
assert(efun5("abc",1) == "abc");
assert(efun5([0,1,2]) == [2,1,0]);  // except it also accepts an array of ints as argument.


Note:
as said before, functions are tested in the same order they were passed as arguments. So a function can 'swallow' arguments that could have been accepted by another, downstream function.

template adaptFun (alias pre,alias fun,alias post = "a")
A simple adapter, when you have a complicated function you do not want to touch (or cannot) touch. It applies the pre preprocessing to the arguments, calls fun and then postprocess the result. The default for post is "a", that is the identity string function. So the two args version of adaptFun just deals with adapting the arguments.

template powerFun (alias fun,size_t n)
The composition 'power' of a function: fun(fun(fun(x)...)), n times. n == 1 is the same as fun and n = 0 is the identity function (just returns the arguments).

Example:
int inc(int i) { return i+1;}
string conc(string s) { return s ~ s;}

alias powerFun!(inc, 5) plus5; // calls inc(inc(inc(inc(inc(t))))), so returns t+5
alias powerFun!(inc, 1) plus1;
alias powerFun!(inc, 0) plus0;

assert(plus5(4) == 9);
assert(plus1(4) == 5);
assert(plus0(4) == 4);

alias powerFun!(conc, 2) conc2;

assert(conc("abc") == "abcabc");
assert(conc2("abc") == "abcabcabcabc");
assert(conc2("abc") == conc(conc("abc")));


DefaultValues!(fun,arity!(fun),D) withDefaultValues (alias fun, D...)(D defaults);
DefaultValues!(fun,arity,D) withDefaultValues (alias fun, size_t arity, D...)(D defaults);
Takes a function and store default values for its last arguments. For a n-arg function, you can provided d default values, d being between 0 and n. These values will be applied to the last d arguments.

Example:
int foo(int i, int j, double k) { return i+j+to!int(k);}
auto dfoo = withDefaultValues!(foo)(2,1.5); // two default values provided -> 2 for j and 1.5 for k
                                            // so dfoo can accept 1, 2 or 3 arguments.

assert(dfoo(1)         == foo(1, 2, 1.5)); // 1 arg given -> dfoo use two defaults
assert(dfoo(1, 1)      == foo(1, 1, 1.5)); // 2 args -> one default
assert(dfoo(1, 1, 0.5) == foo(1, 1, 0.5)); // 3 args -> no default
Most of the time, withDefaultValues will determine the arity of your function. In case of doubt, you can provide it as a second template argument, like this:
A bar(A,B)(A a0, A a1, B a2, Tuple!(A,B) a3) { return a0;} // template function, withDefaultValues cannot determine the arity is 4
auto dbar = withDefaultValues!(bar, 4)(2, tuple(2, 3.14));


TODO:
No, that should be possible now that I have a template to determine the arity even of template functions.

template construct (Struct) if (is(Struct == struct))
template construct (Class) if (is(Class == class))
Accepts a class or struct name as template argument and creates a factory function that creates the corresponding class/struct. It allows one to map a constructor on a range, to create a range of classes. It's not possible normally.

Example:
class C {
    int i;
    this(int _i) { i = _i;}
}

auto arr = [0,1,2,3];

// auto m = map!C(arr); // does not work.
alias construct!C CC;
auto m = map!CC(arr); // works;
// m is like [new C(0), new C(1), new C(2), new C(3)]
What's fun is when you use it on many-args constructors or structs:
struct S { int i; double d;}

alias construct!S CS;

auto s = tmap!CS([0,1,2,3], [-1.1,-2.2,3.3,4.]); // Yeah, tmap
assert(equal(s, [S(0,-1.1), S(1, -2.2), S(2, 3.3), S(3, 4.0)]));


ReturnType!(fun) arrayify (alias fun)(CommonType!(ParameterTypeTuple!(fun))[] args);
Transforms a function accepting (T, T, T, ...) into a function accepting (T[]). The new function will consume as many arguments as needed, but won't throw if there are more.

Example:
int foo(int i, int j, int k) { return i+j+k;}

alias arrayify!foo afoo;
assert(afoo([1,2,3]) == 1+2+3);


template rangify (alias fun) if (isFunction!(fun) && is(CommonType!(ParameterTypeTuple!(fun))))
Transforms a function accepting a (T,T,T,...) into a function accepting a range of Ts.

template tuplify (alias fun)
Transforms a function into a tuple-accepting function. Useful to map a standard function on a tuple-producing range. A parameterless function (zero args) is left untouched.

See Also:
tmap, tfilter, comp and pComp in dranges.algorithm.

Example:
string foo3(int a, string b, double c) {
    return to!string(a) ~ "+" ~ b ~ "+" ~ to!string(c);
}

auto tfoo3 = tuplify!foo3;
auto t = tuple(1, "a", 3.0);
auto result = tfoo3(t);
assert(result == "1+a+3");

string foo() {
    return "aha";
}
auto tfoo = tuplify!foo;
assert(tfoo() == "aha");


ReturnType!(fun) addArgs (alias fun, T...)(ParameterTypeTuple!(fun) args, T newArgs);
A simple adaptor for fun, making it accept supplementary arguments of type T....

See Also:
makeVariadic.

ReturnType!(fun) makeVariadic (alias fun)(ParameterTypeTuple!(fun) args,...);
Takes a standard function, and makes it variadic: it will accept any number of surnumerary arguments of any type after the 'normal' ones that it had before. It's useful to 'adapt' a function to a range (with automatic unpacking of tuples, like for tmap).

Example:
int foo(int i) { return i;}
alias makeVariadic!foo vfoo;
auto i = vfoo(1, 2,3,'a', "hello there!");
assert(i == 1);


template CompatibilityFuncArgs (alias fun,ARGS...) if (isFunction!(fun))
Is true iff fun can be applied on the TypeTuple ARGS.

Example:
assert(CompatibilityFuncArgs!("a+b", int, int)); // 'string' function are templated by unaryFun or binaryFun
                                                 // They will always be compatible with their args
assert(CompatibilityFuncArgs!(binaryFun!"a+b", int, int));

int foo(int a, double b) { return a;}
assert(CompatibilityFuncArgs!(foo, int, double));
assert(CompatibilityFuncArgs!(foo, int, int)); // You can pass an int as second argument for foo, as it will be converted
assert(!CompatibilityFuncArgs!(foo, double, double));  // But not a double as first arg.
assert(!CompatibilityFuncArgs!(foo, int, string));

int bar() { return 0;}
assert(CompatibilityFuncArgs!bar); // For bar, no args...
assert(CompatibilityFuncArgs!(bar, TypeTuple!())); // For bar, no args...

assert(CompatibilityFuncArgs!((int a) { return -a;}, int)); // Works for anonymous functions


template naryFun (string fun,uint Nparam)
template naryFun (string fun)
template naryFun (alias fun,uint Nparam) if (!is(typeof(fun) : string))
template naryFun (alias fun) if (!is(typeof(fun) : string))
A generalization of std.functional.unaryFun and .binaryFun for as many params as you need, in the 'a' - 'z' (included) range. You can indicate the desired final arity if you want, but otherwise a compile-time heuristics tries to determine the string's 'arity'. As for unaryFun and binaryFun, 'a' means first argument, 'b' the second and so on. As for unaryFun and binaryFun, it creates a templated function, with the type of each parameter left undecided. As for unaryFun and binaryFun, it does not change fun if it's already a function.

Examples:
alias naryFun!("a+b*c-d") test4;  // Creates a templated 4-args function test4(A, B, C, D)(A a, B b, C c, D d) { return a+b*c-d;}
assert(test4(1,2,3,4) == 3);        // instantiate test4!(int, int, int, int)
assert(test4(1.0,2.0,3,4) == 3.0);  // instantiate test4!(double, double, int, int)

alias naryFun!("a+b",3) test3;      // You can create a fun with more args than necessary, if you wish
assert(test3(1,2,100) == 3);        // without the 3, naryFun!"a+b" would create a binary function.
assert(test3(1.0,2.0,100) == 3.0);

alias naryFun!"sin(a)+cos(b)*c" testsincos; // functional.d imports a lot of other D modules, to have their functions accessible.

alias naryFun!"tuple(a,a,a)" toTuple;
assert(toTuple(1) == tuple(1,1,1));

alias naryFun!"a.expand[1]" tuple1; // tuple1 will be created, but can be used only on types defining a .expand field.
assert(tuple1(toTuple(1)) == 1);

alias naryFun!"[b,a,c]" arrayTwister; // will return a static array
assert(arrayTwister(0,1,2) == [1,0,2]);

alias naryFun!"f" projection6; // 'a' -> 1 arg, 'b' -> binary, ..., 'f' -> 6-args function. In this case, returning only its sixth argument.
assert(projection6(0,1,2,3,4,5) == 5);

alias naryFun!"3" test0;               // A 0-arg function. It's exactly: int test0() { return 3;}
assert(test0 == 3);                    // Constant return
assert(is(typeof(test0) == function)); // But it's a function, not a constant.

int foo(int a, int b) { return a*b;}
alias naryFun!(foo) nfoo;           // function test
assert(nfoo(2,3) == 6);

int bar() { return 1;}
alias naryFun!bar nbar;             // 0-arg function test
assert(nbar == 1);


template Prepare (alias fun,T...)
Internal template to transform a function or a 'string' function to be applied on a tuple. The T... part must contains the information about the args types. It's used to instantiate the correct function from the template function created by naryFun.

It's used internally by all the tuple-mapping functions: tmap, tfilter, etc.

Page was generated with on Fri Nov 12 11:55:09 2010