Tuesday, November 12, 2013

Baby Steps Towards Currying in Dart


In the functional programming chapter in Dart for Hipsters, I make the following observation:
At the time of this writing, Dart lacks facilities (for example, reflection) to support sophisticated functional concepts such as currying or combinators. That said, it is already possible to perform partial function application in Dart.
Much of that statement is based on very early research that I did on the topic and have not revisited since. I am fairly certain that is no longer the case—especially after seeing what the Angular.dart folks have done. So it seems worth revisiting before a new edition of the book hits the virtual bookshelves.

I am not sure that I can quite put together a full currying example tonight. Instead, I am just going to attempt the parts.

First, I need a way call functions with arbitrary arguments. For partial application, I have been using the classic three parameter add() function:
add(x, y, z) {
  return x + y + z;
}
The idea behind currying is to break this into three functions such that it can be invoked as addCurried(x)(y)(z). For that to work, especially to be able to generalize to functions that can take more than three arguments, I need a way to call functions with an arbitrary number of parameters. Well, new since I first wrote the book is Function.apply() which lets me do just that:
make2(fn, arg1) {
  return (x, y) {
    return Function.apply(fn, [x, y, arg1]);
  };
}
This make2() function makes a function that takes 2 arguments. It uses those two arguments to call the supplied three argument function with those two arguments, plus a third argument that can be defined when the function is created:
var add100 = make2(add, 100);
add100(1, 1); // => 102
That is all well and good, but I need a way to know with how many arguments a particular function is called. For that, I will need to make use of mirrors. Tonight, I start with the Inovocation object that is available in noSuchMethod(). I do not know if I can combine the two efforts, but this seems a reasonable first step:
class Foo {
  noSuchMethod(args) {
    print("called with: ${args.positionalArguments}"):
  }
}
The args object is an InvocationMirror object which has, among other properties, the list of positional arguments in positionalArguments. If I call an instance of this object with three parameters, it prints out a list of three values:
new Foo().bar(1, 2, 3);
// called with: [1, 2, 3]
Since this is a list, and since Function.apply() conveniently takes a list of arguments, I can create a poor man's curry with:
class Foo {
  noSuchMethod(args) {
    if (args.positionalArguments.length == 3)
      return Function.apply(add, args.positionalArguments);
    if (args.positionalArguments.length == 2)
      return (x) {
        var _args = [x]..addAll(args.positionalArguments);
        return Function.apply(add, _args);
      };
    if (args.positionalArguments.length == 1)
      return (x, y) {
        var _args = [x, y]..addAll(args.positionalArguments);
        return Function.apply(add, _args);
      };
  }
}
That's pretty ugly, but each of the following result in the same value:
new Foo().bar(1, 2, 3); // 6
new Foo().bar(1, 2)(3); // 6
new Foo().bar(1)(2, 3); // 6
That's still not quite right for currying as new Foo().bar(1) should really return a function the method with only one parameter. Still, I can do two of the things necessary for arbitrary currying in Dart. I still need a way to inspect a supplied function like add() to see how many arguments it takes. For that, I think the work the Angular.dart folks have done will suffice. In the end, I still do not have a sense as to whether or not it is possible to do this pretty. But so far, it looks like it may at least be possible to do this ugly.

I will pick back up tomorrow.


Day #933

No comments:

Post a Comment