Currying and partial application with JavaScript

Currying and partial application have been famous as one of the most confusing terminologies in the history of functional programming. In fact, many who claim they know or who teach these concepts are themselves confused so much that a lot of resources on the web can be confusing and somewhat wrong.

I hope this article will be the last you ever have to read about currying and partial application. By the end of this article, you would understand and become a JavaScript Ninja with these terminologies.

Currying

  • Currying emphasizes a function whose number of arguments returns the same number of function calls.
  // without currying: This is not a curried function
  add(2,3,4) //=>9 
  // three arguments: 2, 3 and 4, returns a value

  // with currying: This is a curried function
  add(2)(3)(4) //=>9 
  // three arguments: 2, 3 and 4, returns three function calls: (2)(3)(4)
  • Each of the returned functions shall only take one argument
// this is not currying
add(2,3)(4) 
// three arguments: 2,3 & 4, returns two function calls (3 != 2)
// another reason: first function has more than one argument.

const add = cur(2,3) // this is not curried function
const add2 = add(2) // this is not curried either since it inherits a function that contains more than one argument.

const minus = cur(2)(3) // this is a curried function
const minus3 = minus(3) // this is a curried function since the function it inherits is called with one argument per time

Currying is a process and an art

As a process, currying is converting a single function of n (where n is a specific number) arguments into n functions with a single argument. This can be further explained with a scenario as, if a function has three arguments, currying states that it must return 3 functions call - where the number of arguments a function has is called arity.

Curry transformator function

const curry = (fn)=> {
  return curried = (...args) => {
    if(fn.length !== args.length){
       return curried.bind(null, ...args)
    }
    return fn(...args)
  }
} 

//uncurryed add function
function add (a,b){
  return a+b
}

const curAdd = curry(add) //converts uncurryed add function into a curryed function
console.log(curAdd(2)(4))

As an art, currying states that when we write a function, it should only contain one arity and return other arguments individually until the required arguments needed for the operation is generated.

// we should write functions like this
add(a)(b)(c)
// not like this
add(a,b)(f)

Partial Application

Partial application is never concerned about the rule of one arity per se. It emphasizes partially applying some arguments of a function.

// we are partially applying the first argument 2 to the add function
const partialAdd = partial(add, 2) // see that the rule of one arity is lost

Unlike currying that states that its arguments must contain always one arity, partial application states that a function first call contains the function to be used, and a fraction of the argument to be applied with - partial(fntobeused, parameter)

Partial Applicator implementation

const partialize = (fn)=> {
  return partied = (fn, fnarg) => (...restArgs)=> {
    if(fn.length !== ([fnarg, ...restArgs]).length){
       return partied.bind(null, fnarg, ...restArgs)
    }
    return fn(fnarg, ...restArgs)
  }
} 

function add (a,b){
  return a+b
}

const partialAdd = partialize(add)

// this way is commonly used to favour re-usability
const added2 = partialAdd(add, 2)
console.log(added2(3)) //=> 5

//it can be written this way to 
partialAdd(add, 2)(4) // 6

If you only supply a subset of the arguments, you'll get back a function that accepts the rest of the arguments - this is the summary of partial application.

Similarities between currying and partial application

  • They both return a function that respects the one-arity rule. However, currying is more strict with the one-arity rule compare to partial function.
    add(3)(4) // this is curry. It returns a function that took "4" as an argument
    partial(add, 3)(4) // this is a partial application. It returns a function that took "4" as an argument likewise
    

I hope this article have been able to do justice on what Currying is and what Currying is not, likewise for partial application.