3

It seems the curry and partial functions do the exact same thing. (Maybe the only difference is the number of arguments)

Is it just matter of convinience or there is a good reason on having two functions that do kind of similar thing.

  • This is almost the same question as [What is the difference between currying and partial application](http://stackoverflow.com/q/218025/2907849) only without ramda reference. – lonelyelk Dec 12 '16 at 10:19
  • @lonelyelk: ... but because Ramda's `curry` is somewhat non-standard, this might need its own answer. I'll try my own below. – Scott Sauyet Dec 12 '16 at 16:34

2 Answers2

11

A lot of answers from the wider FP community might steer you a little wrong. Ramda's currying seems to me to carry the spirit of currying from ML-style languages into Javascript, but is not strictly the same.

Partial application is probably fairly standard in Ramda. (Disclaimer: I'm one of the Ramda authors.) It's also much easier to describe. Ramda's partial function accepts a function of n arguments and a list of k arguments (for some 0 < k < n), and returns a new function of n - k arguments that will call the original function with your new arguments and the original ones:

const f = (a, b, c, d, e) => a + b + c + d + e;
// f :: a -> b -> c -> d -> e -> a + b + c + d + e

const g = partial(f, [1, 2]);
g.length; //=> 3
g(3, 4, 5); //=> 15
g(3); //=> NaN ≍ 1 + 2 + 3 + undefined + undefined)
// g :: (c, d, e) -> 1 + 2 + c + d + e

The function returned is just a simple function of the remaining parameters. If you call it with too few, it will act as though you called the original function with too few as well.

Currying is a slightly different story. In many languages, a curry function would convert a function of n parameters into a nested sequence of 1-parameter function, so that (a, b, c) => f(a, b, c) transforms into a => (b => (c => f(a, b, c)), which can be written without confusion as a => b => c => f(a, b, c). In Ramda, we are a little more flexible, allowing you to supply as many of the arguments as you choose at a single call, each time returning a function until you have supplied enough total parameters to satisfy the original function, at which point we call it and return that value. It's probably easier to explain with examples:

const f = (a, b, c, d, e) => a + b + c + d + e;
// f :: a -> b -> c -> d -> e -> a + b + c + d + e

const h5 = curry(f);
h5.length; //=> 5

const h3 = h5(1, 2);
h3.length; //=> 3
h3(3, 4, 5); //=> 15

const h2a = h3(3);
h2a.length; //=> 2
h2a(4, 5); //=> 15

const h2b = h5(1, 2, 3);
h2b.length; //=> 2
h2b(4, 5); //=> 15

const h2c = h5(1)(2, 3);
h2c.length; //=> 2
h2c(4, 5); //=> 15

const h2d = h5(1)(2)(3);
h2d.length; //=> 2
h2d(4, 5); //=> 15

const h1a = h3(3, 4);
h1a.length; //=> 1
h1a(5); //=> 15

const h1b = h2a(4);
h1b.length; //=> 1
h1b(5); //=> 15

// h5 :: (a, b, c, d, e) -> a + b + c + d + e
//    :: (a, b, c, d) -> e -> a + b + c + d + e
//    :: (a, b, c) -> (d, e) -> a + b + c + d + e
//    :: (a, b, c) -> d -> e -> a + b + c + d + e
//    :: (a, b) -> (c, d, e) -> a + b + c + d + e
//    :: (a, b) -> (c, d) -> e -> a + b + c + d + e
//    :: (a, b) -> c -> (d, e) -> a + b + c + d + e
//    :: (a, b) -> c -> d -> e -> a + b + c + d + e
//    :: a -> (b, c, d, e) -> a + b + c + d + e
//    :: a -> (b, c, d) -> e -> a + b + c + d + e
//    :: a -> (b, c) -> (d, e) -> a + b + c + d + e
//    :: a -> (b, c) -> d -> e -> a + b + c + d + e
//    :: a -> b -> (c, d, e) -> a + b + c + d + e
//    :: a -> b -> (c, d) -> e -> a + b + c + d + e
//    :: a -> b -> c -> (d, e) -> a + b + c + d + e
//    :: a -> b -> c -> d -> e -> a + b + c + d + e

Because curry is so much more flexible, I rarely use partial myself. But there are people who are, ahem, partial to it.

Community
  • 1
  • 1
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
-2

As you briefly mentioned, curry function can take a function with n arguments and return n functions with one argument. Currying is an essential tool to compose functions into higher order functions.

Partial applications of functions is a type of currying. In fact, if you look into Ramda source code you'll see that the partial function was implemented using curry function.

var _arity = require('./_arity');
var _curry2 = require('./_curry2');


module.exports = function _createPartialApplicator(concat) {
  return _curry2(function(fn, args) {
    return _arity(Math.max(0, fn.length - args.length), function() {
      return fn.apply(this, concat(args, arguments));
    });
  });
};

Also, take a look to this question that explain the different fundamentally.

Community
  • 1
  • 1
bman
  • 5,016
  • 4
  • 36
  • 69
  • 1
    This in incorrect: "Partial applications of functions is a type of currying." Currying is the *transformation of a function* of a type such as `(a, b, c) -> d` into a function of type `a -> b -> c -> d`. – davidchambers Dec 12 '16 at 09:01