Currying is a very powerful concept in functional programming. Once you understand how it works and what is does you won't be able to live without it anymore. I first read about currying 5 years ago, while reading book about JavaScript design patterns. It seemed cool, but I could not imagine a real-world use case for it. About 7 months ago, when I became "fully functional" I started using it extensively and nowadays I use it on daily basis and cannot imagine writing the code without it anymore.

What is currying ?

To borrow a phrase from Vasily Vasinovs article: "Currying is the process of decomposing a function of multiple arguments into a chained sequence of functions of one argument". There are various implementations of currying, but I prefer the ones from lodash or ramda. I use them alternately and they seem to have identical implementation. Lets see some code now.

const { curry } = require ( 'lodash/fp' ); const compute = curry((a, b, c) => a + b + c); compute( 1 )( 2 )( 3 );

How do I use it ?

Yeah, that seemed cool. But how do I use this in a real world application ? Again let me show you some code.

const { curry } = require ( 'lodash/fp' ); const { assoc } = require ( 'ramda' ); const updateProductLastView = curry( (timestamp, product) => { return product.map(assoc( 'lastViewed' , timestamp)); }); server.route({ method: 'GET' , path: '/api/products/{id}' , handler(request, reply) { const { productRepository } = request; reply( productRepository.findById(request.params.id) . then (updateProductLastView(Date.now())) . then (asyncTap(productRepository.update)) ); }, });

What is happening here ?

We have a route definition for hapi.js of API resource, that is returning product by its ID. We defined a curried function updateProductLastView and then we use it in route definition. Notice how we call the function with only one parameter, and then let promise apply the second parameter (product object returned from database) by calling the function that was returned by calling updateProductLastView(Date.now()).

What are the limits ?

About a month ago I hit the use-case with default function params where applying currying concept was a no-go. Then I bumped into Vasily Vasinovs article about currying and partial application in Scala. During reading this article I realized that Vasily introduces a Scala concept called implicits to deals with default params in curried functions. I immediately had the eureka moment and started to experimenting in JavaScript.

const { curry, curryN } = require ( 'lodash/fp' ); const computeV1 = curry((a, b = 2 , c) => a + b + c) const computeV2 = curryN( 3 , (a, b = 2 , c) => a + b + c); computeV1( 1 )()( 3 ); computeV2( 1 )()( 3 );

It doesn't matter if you use curry either from ramda or lodash, currying function with default parameters will not work. The reason is that the function with default param will report its arity based on the position of the first default param.

const fn1 = (a, b = 1 , c) => a + b + c; const fn2 = (a, b, c = 2 ) => a + b + c; const fn3 = (a = 1 , b, c) => a + b + c; fn1.length; // => 1 fn2.length; // => 2 fn3.length; // => 0 ﻿﻿

The solution #1

Ok so the currying and default params just don't play along. We don't have implicits in JavaScript as Scala does. So what do we do ? Let's get back to basics and write this function without default params.

const { curry, defaultTo } = require ( 'lodash/fp' ); const computeV3 = curry((a, b, c) => { const defaultB = defaultTo( 2 , b); return a + defaultB + c; }) computeV3( 1 )( null )( 3 ); computeV3( 1 )( undefined )( 3 ); computeV3( 1 )()( 3 );

Handle your default value in the body of the function itself and call the function with an empty value, in this case null or undefined (empty value). Calling the function without arguments is like not calling the function at all (you end up in computeV2 scenario).

The Solution #2

While the above solution works, it forces you to forget the notion of default params. And that is really unfortunate. More elegant solution to this problem is using curryN either from ramda or lodash and provide the arity of the curried function explicitly. If you want to apply the default value of the param, you must explicitly pass the undefined (notice null doesn't work in this usecase) value at the right possition.

const { curryN } = require ( 'lodash/fp' ); const foo = curryN( 3 , (a, b = 2 , c) => a + b + c); foo( 1 )( undefined )( 3 );

In my opinion this solution is cleaner, more elegant and you can make a convention in your codebase to use curryN instead of curry . Then you don't need to pay attention how you define your functions or if they have default params.

Update (18.03.2017)

It seems that there is more elegant solution to this problem conceived by Kyle Simpson. Using FPO library your code can look like this:

function foo ( x,y = 2,z ) { console .log( x, y, z ); } var g = FPO.curry( { fn: FPO.apply( {fn: foo} ), n: 2 } ); g( {z: 3 } )( {x: 1 } );

You can read more about his reasoning in this article.