Sunday, January 1, 2012

Partial Application in Dart

‹prev | My Chain | next›

One of the things that I have been unable to figure out with Dart is if functions can take arbitrary numbers of arguments. As I found last night, functions in Dart can take any number of optional arguments:
  f(a, [b1, b2, b3, b4, b5, b6, b7, b8, b9, b10]) {
    // ...
  }
But there does not seem to be any way to work with arbitrary numbers of arguments. That lack would seem to limit Dart's functional programming abilities a little, but it is still a very new language.

To explore this, I take a look a partial application and currying (there is a great article on MSDN on this topic). First up, partial application, which is easier for my brain to grasp. Given a function that adds three numbers together, a partially applied function is one that hard-codes one of those three numbers, effectively creating a function that takes two arguments:
main() {
  add(x, y, z) {
    return x + y + z;
  }

  add1(x, y) {
    return add(1, x, y);
  }

  print("add: " + add(1, 2, 3));

  print("add1: " + add1(2, 3));
}
(try.dartlang.org)

In there, the add1 function has been partially applied to the more general add function which adds three numbers. The add1 function now adds "1" to the two arguments supplied to it. The result of that script is:
➜  command_line git:(master) ✗ dart partial01.dart
add: 6
add1: 6
It would be a pain to have to define an add2, add3, and add10 in the same way. Rather I can define a makeAdder1 that makes and "adder" function that partially applies one argument:
main() {
  add(x, y, z) {
    return x + y + z;
  }

  makeAdder1(fn, arg1) {
    return (y, z) {
      return fn(arg1, y, z);
    };
  }

  var add10 = makeAdder1(add, 10);

  print("add: " + add(1, 2, 3));

  print("add10: " + add10(2, 3));
}
(try.dartlang.org)

Now I can create any number of partially applied adder functions by assigning new functions to the return value of the makeAdder1 function. That makeAdder1 function takes two arguments: a function and the argument to be partially applied. It then returns a function that takes 2 arguments—the partially applied function.

The problem here is that I cannot make this any more general. There is no way for me to write a "maker" function that would work with underlying functions with 3 arguments as well as work with functions that take 4, 5, or 6 arguments.

A bit frustrated, I call it a night here. Up tomorrow, I may take a shot at currying, although I am hard-pressed to see how that is going to be useful in Dart (at least today).


Day #252

5 comments:

  1. I guess you could use named arguments as "arbitrary numbers of arguments"?

    See: http://blog.sethladd.com/2011/12/learning-functions-for-dart.html

    f(a, [b1, b2, b3, b4, b5, b6, b7, b8, b9, b10]) {
    // ...
    }

    Calling with arbitrary parameters:

    f('foo', b8:'bar', b3:'baz');

    ReplyDelete
  2. Of course I misread it and that isn't "arbitrary".

    You would need to pass an array of parameters or other type of object for that.

    ReplyDelete
  3. Dart did have variadic functions for a while (including JS-style rest and spread operators). We took it out to simplify things while we hammered out named arguments. My understanding is that trying to have both at the same time made a bunch of stuff overly complex so in the absence of a clean solution, we just yanked it for now.

    We may get them back at some point, or we may not. So for we haven't missed them too much, though it does make some combinator-like functions harder to write like you describe here.

    ReplyDelete
  4. @Rodrigo Yah, I'll have to content myself with faking it via Arrays/Maps for the time being.

    @Bob That makes sense, thanks for the info. Given the choice between optional arguments and variable arity, I'd definitely go with the former as well. In practice, I use optional arguments far more often.

    Still, it's good to be able to have combinators in the toolbox. That said, variatic functions seem at-odds with "structured" code, so I'll definitely be interested to see how it all plays out.

    ReplyDelete