23 comments

[ 6.6 ms ] story [ 88.1 ms ] thread
Seems like a cool use of the technology.
being a javascript/typescript developer with little knowledge about functional programming, this article renewed my interest in the matter. I would be interested to see some performance tests though, to get a feeling just how much 'a little performance cost' costs
I was thinking about whipping together a perfJS for the curry function and putting it in the post but ended up not... I might make one and post it back here.

---

UPDATE: I made this jsperf: http://jsperf.com/curry-function

There might be better things to test, but the results were actually unexpected. Currying "manually" with nested functions is actually slower than using my "curry" function.

As I mentioned in my post, if you are touching the DOM at all, I really doubt you will see much of a performance hit from using this...

interesting! tnx for the extra effort to put that up.
Unless you're in tight loops you wont notice this perf hit. Disk, Network, and DOM manipulation will be the 99% time sinks.
That doesn't justify degrading the rest of your code base.
Me too. I thought long and hard about how I could use functional programming (aside from the usual callbacks) and came to the conclusion that functional programming is more composable - that's its strength - how you can combine stages in a pipeline. It's all centered around data flow instead of execution flow.

One example would be jQuery or Underscore - how you can chain operations with the "." operator, or another common example is how we use the pipe " | " operator in the shell to compose processes. I use the latter quite a lot and am proficient at making pipelines.

By contrast, procedural programming relies a lot on global variables and that makes a mess of reusing pieces of code from an app into another.

I wouldn't say that procedural code relies on global variables, but I would say that we find ourselves worrying about execution order a lot more when using procedures rather than pure functions.

If we care about execution order, we tend to avoid higher-order patterns which may defer execution (eg. compose) or give a nondeterministic order (eg. map). If we avoid higher-order patterns, we end up hard-coding an awful lot of control-flow, which makes our code less re-usable.

Simplistic attempts to avoid this, introduce a small amount of higher-order behaviour, like passing around 'callbacks', but this can be cumbersome and add a lot of boilerplate. Of course, the solution to avoiding this is to use even more powerful higher-order functions (like monadic bind) to handle the callbacks for us, but since we're trying to avoid as much higher-order behaviour as possible, this tends not to be done.

Interesting, especially aside about partial application ("holes") which I've not seen done in JS before.

I've been using my own JS currying implementation in a few projects[1], which pretty much matches the implementation in the article: count the function's parameter number and build up argument lists in closures until we have enough to call the function, then pass them all in.

However, when I was implementing the same thing in PHP[2] I discovered a nice alteration we can make: instead of passing all arguments to the curried function, we should only pass the minimum number. If we have any left over, we should pass them to the return value. This lets us chain even more things together[3]. For example:

    // "c" is our currying function
    var id     = c(function(x)       { return x;         });
    var triple = c(function(x, y, z) { return x + y + z; });

    // These work with both currying functions
    id(triple)('Hell', 'o Wor', 'ld');
    id(triple)('Hell')('o Wor', 'ld');
    id(triple)('Hell', 'o Wor')('ld');
    id(triple)('Hell')('o Wor')('ld');

    // These only work with the altered version
    id(triple, 'Hell', 'o Wor', 'ld');
    id(triple, 'Hell')('o Wor', 'ld');
    id(triple, 'Hell', 'o Wor')('ld');
    id(triple, 'Hell')('o Wor')('ld');
[1] http://chriswarbo.net/index.php?page=news&type=view&id=curry...

[2] http://chriswarbo.net/index.php?page=news&type=view&id=admin...

[3] http://chriswarbo.net/index.php?page=news&type=view&id=admin...

This is very interesting. I'm not so sure this wouldn't trip me up some times though. What if the first argument you are expecting, is supposed to be a function? I would think that would be a pretty common scenario...

Unless I'm not quite getting what you mean?

EDIT: I see that this would only happen if you passed in more arguments than expected, thus it wouldn't be a problem.

Very cool! I might update mine to work this way.

Indeed, the behaviour should be identical when too few or exactly enough arguments are given.

The way I see it, if we're not given enough arguments we introduce wrappers around our function to accept the rest. With this alteration, when we're given too many arguments we eliminate wrappers from around our result by passing them the rest.

This hints that they might be 'dual' notions, in a Mathematical sense. Maybe I should dub it "cocurrying"? ;)

> This hints that they might be 'dual' notions, in a Mathematical sense. Maybe I should dub it "cocurrying"?

After a little more thought I've realised that this is exactly uncurrying of return values.

When we uncurry, we take a bunch of arguments at once and supply them one-at-a-time to our function, for example "uncurry(foo)(a, b, c, d)" becomes "foo(a)(b)(c)(d)".

Note that this is identical to the calling convention of a curried function, hence the name uncurrying. In this way, it makes sense to uncurry the return value of curry:

    // Pass 3 values to a curried function which just-so-happens to return
    // other functions
    curry(function(w, x) {
      return function(y) {
        return function(z) {
          return w + x + y + z;
        };
      };
    })(1, 2, 3, 4);

    // Take the first 2 arguments to be w and x
    (function(w, x) {
      return function(y) {
        return function(z) {
          return w + x + y + z;
        };
      };
    })(1, 2)(3, 4);

    // Apply the first function
    (function(y) {
      return function(z) {
        return 1 + 2 + y + z;
      };
    })(3, 4);

    // The above version will ignore 4 and wait for another z.
    // This is why we need to uncurry it.
    uncurry(function(y) {
      return function(z) {
        return 1 + 2 + y + z;
      };
    })(3, 4);

    // Now we can execute it properly
    (function(y) {
      return function(z) {
        return 1 + 2 + y + z;
      };
    })(3)(4);

    (function(z) {
      return 1 + 2 + 3 + z;
    })(4);

    10;
Now, given our implementations of curry, we don't actually have to uncurry a function explicitly: we can call "foo(a, b, c, d)" even if "foo" is curried. Hence we can just pass all the arguments straight into the return value assuming that it is uncurried.

This will work for regular Javascript functions and those which we've curried. The only thing it won't work for is functions which have been hard-coded in a curried form; these will need to be sent through an uncurry function first (which we can do via composition).

"In most web applications the "bottle-neck" is going to be DOM interaction. It is very unlikely that you will notice a performance hit at all."

uhhh, 2 wrongs don't make it right?

"It is very unlikely that you will notice a performance hit at all."

Until you do..

--

I could never justify using this stuff at work. It's inefficient, unfamiliar to most JS developers and even if it did pass a peer review, nobody else would actually want to maintain it.

> I could never justify using this stuff at work. It's ... unfamiliar to most JS developers and even if it did pass a peer review, nobody else would actually want to maintain it.

The same could be said for any API.

Currying is actually very unobtrusive; the only time a curried function behaves differently to its uncurried counterpart is when it's given a 'wrong' number of arguments. The benefit is never having to perform manual eta-expansion (ie. any time we write a redundant wrapper like "function(x) { return bar(a, b, c, x); }").

As for efficiency, I default to having the machines doing things to save developer's time and only do things the other way around when it's untenable (or for fun).

Seems to me that using the functional style it's really important to document the types (done in the article with the //+ lines).

Otherwise it will be hard to make the types line up.

Also there are functions in javascript which do different things depending on what the type of the argument is (or do different things depending on how many arguments are passed in; those kinds of functions always have irked me), so it would be hard to document exactly what the "type" of those functions are.

@platz, yes, this is correct. When currying and/or composing functions, it becomes more difficult to determine the input/output types of the function since the function signature won't be right there. I'm borrowing the `//+` syntax from Brian Lansdorf, since I saw him use it and quite like it. He mentioned he has "a lot to say on the topic" of commenting / type sigs, but I haven't heard him speak specifically on that.

Also, for functions that do different things depending on how many arguments are passed in, you would never want to curry these. The curry function relies on the function passed in expecting a specific number of arguments.

Part of me thinks that if you're going to pursue this style to it's extreme, you might as well just be better off using something like purescript

http://purescript.readthedocs.org/en/latest/intro.html#hello...

I haven't had a chance to try purescript yet, but I have looked at it. Really though, I love JavaScript, and don't have much desire to use another language that that transpiles into it...
Fair enough, there's always headaches with transpilers; I for one have been suspicious of all the coffeescript+derivatives.
Awesome job! I was trying to understand curry by learning Haskell but you summed it up perfectly.

What is the difference between curry and partial? Is a partial just a curry that hasn't filled in all the arguments yet?

As it exists in Haskell, yes, that's what partial application is — the result of applying a curried function to less than the full number of arguments. Some other languages have a more general form of partial application where you can partially apply arguments in non-sequential order, which isn't related to currying and instead just means creating a wrapper function that calls the original function with certain arguments filled in.
I assume you mean "partial application"?

"Currying" turns a multi-argument function into a chain of one-at-a-time wrappers. If we curry a 5-argument function "foo(a, b, c, d, e)", we get a nesting of 5 functions, each accepting one argument "foo(a)(b)(c)(d)(e)". The implementation in the article, as well as my own, go slightly further and also allow curried functions to accept multiple arguments at once, eg. "foo(a, b, c, d, e)"; this is just for convenience though, a "real" curried function must accept arguments one at a time. Note that in Haskell syntax, there is no difference between the two: "foo a b c d e".

Alternatively, "partial application" takes some argument values now, returning a function which accepts the rest later. If we partially-apply a 5-argument function with, say, its first 2 arguments, we get back a 3-argument function, eg. "papply(foo, a, b)(c, d, e)".

Note that we must use partial application explicitly whenever we want to supply a few more arguments; curried functions keep track of this themselves.

As an aside, you mention Haskell. Note that Haskell functions are already curried; in Haskell, "curry" and "uncurry" convert between functions which accept separate arguments and functions which accept one big tuple of arguments.