dranges.lambda

This module is a small expression template library to create anonymous functions (aka, lambdas) in a syntax reminiscent of std.* 'string' functions or what is used in other programming languages (like Scala, for example).

Future arguments are represented as _0, _1, _2, or simply _. Anonymous functions are automatically constructed by putting them in arithmetic expressions. Here are a few examples:
auto l1 = _ + 1;
auto l2 = _0 + _1;
auto l3 = _2[_0.length-1.._1.length+1];
auto l4 = _2 ~ _3;

auto head = _[0]; // Or _.front
auto tail = _[1.._.length];
Their main point is to be used in map/reduce/filter calls in lieu of 'string' functions:
auto arr = [0,1,2,3,4];
auto plusOne = map!(_ + 1)(arr);
auto sum = reduce!(_0 + _1)(arr); // instead of reduce!("a + b")(arr);
_0 + _1 is a completly templated function that waits for two arguments and return their sum. Lambdas are always generic in all their arguments and are automatically curried. _0 + _1 can be called with two arguments, but also with one. In that case (_0 + _1)(1) puts the 1 in place of all _0s in the expression and returns the resulting lambda: 1 + _0. This new lambda can itself be called with another argument to give the sum. This allows for some nifty tricks like:
// create a range of functions: [ _+0, _+1, _+2, ...]
auto funRange = map!(_0 + _1)(arr);
foreach(fun; funRange) writeln(fun(10)); // writes 10,11,12,13,14.
Features and authorized expressions:
  • Any basic binary and unary expression should work.
  • == is OK. != is not, though (see below).
  • opIndex is there, and slices too.
  • opDispatch is used to allow expressions like : .length.
  • Compared to 'string' functions, they can be passed around, are real callable objects and so should be compatible with all your usual idioms concerning functions.
  • compared to template anonymous function, like (i) { return i+1;} they can be passed around, returned as results from other functions, etc. In D, closures can be returned but not templated closures. Here you can, at least for the expressions described above.
  • They are composable. If you have two lambdas, you can sum them, call one with another, etc. You cannot do that with 'string' functions.
  • They are not limited to two arguments. In fact, the real syntax for _0 &co is Arg!0, Arg!1, etc. The _x shown here are just alias for your convenience. There is no limit to the number of arguments. And remember: the resulting expression will be fully generic and curried.


It's just an afternoon work really, so be prepared for bugs and such. As of this writing, the main limitations are:
  • No opCmp (<, <=, >, >=). I couldn't find a way to do them that doesn't produce infinite template expansion, due to the way DMD rewrites a < b as a.opCmp(b) < 0: the < 0 part triggers another expansion,etc. This *really* annoys me, as it severely limits the interest of the library: you cannot do filter!(_ < 1)(range), which was one of the main motivations for writing this module. Any help would be appreciated.
  • No opCall. That is, you cannot do _0(_1). This is by design, because all the lambdas are callable structs: 0(1) gets 0 called with _1, it does not construct another lamda. I could easily introduce a CallExpr constructor, but that'd mean calling lambdas with another syntax that the call operator (), which rather defeats the goal of this module. Maybe I could test for the arguments being expressions or not...
  • No !=, because a!=b is rewritten as !(a.opEquals(b)). But a.opEquals(b) is a lambda, not a boolean. That makes the compiler chokes because it cannot implicitly convert the lambda to a boolean. As there is no opImplicitCast in D, I'm stuck.
  • No opCast(type). It seems that in cast(type)lambda, the compiler does not construct the CastExpr I want it too, but try to directly cast lambda into a type...
  • No expression with standard functions. That is, no lambda like: sin(_)+cos(_). That's because sin and cos want a real, not a lambda. A nasty workaround would be to use the method call syntax: _.sin + _.cos and play with opDispatch. But I find the resulting syntax quite ugly.


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