DEV Community

Cover image for Functional Programming 101: Currying Pattern
Carlos Gómez Suárez
Carlos Gómez Suárez

Posted on • Updated on

Functional Programming 101: Currying Pattern

Core Concepts of Functional Programmming.

My story with OOP and Functional Programming

The first programming language I learn was Java, so obviously I needed to learn the Object Oriented Programming (called OOP from now on) too, although today Java allows some Functional Programming concepts too.

When I was learning the core concepts of OOP I sat down on my desktop and I was reading things like encapsulation, yeah, inheritance, oh yeah, and suddenly "Dude, what the heck is polymorphism?". The concept was painful at first time, but applying it was easier than I thought. After time, I learn Python using POO (it was a weird result), a bit of C#, C++, Ruby... I mean, I explored just using OOP. And finally, I learned JavaScript, and yeah, I use OOP again. For any reason, on JavaScript the OOP don't convinced me at all (I was bored to use it too). I think that the JavaScript versatility get lost when I use OOP. Then ES6 appears on my life and it changes everything. I noticed that ES6 allowed Functional Programming, so I decided to learn about using JavaScript (with TypeScript) with functional programming paradigm. When I was learning the core concepts of functional programming I sat down on my desktop and I was reading things like pure functions, yeah, high order functions, and suddenly "Dude, what the heck is a currying function?". Again, the concept was painful at first time, but applying it was easier than I thought.

Today, I will explain you what is a currying function with my own words using TypeScript in this section called "Functional Programming 101".

Core concept of Currying Function

The currying function is a function that returns another function which takes only one parameter at a time.

Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c). [1]

function currying(a) {
    return function(b) {
        // do somethig with the assigned 'a' var
        // by using another function that pass 'b' var.
        return a + b; // for example
    }
}
Enter fullscreen mode Exit fullscreen mode

This is a very simple example that you could found searching on the web.
So if we do something like:

console.log(currying(1)); // function currying(b)
Enter fullscreen mode Exit fullscreen mode

we obtain as a result a function. Everything is ok here. So, has sense if we do:

console.log(currying(1)(1)) // 2
Enter fullscreen mode Exit fullscreen mode

The currying concept works thanks to the JS closures.

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time. [2]

Advantages

This simple concept is so powerful when you need to use it, and the code is cleaner. Maybe for some librabries, using exported currying functions would be a great idea (if it is possible) or in some scenarios it allows more flexibility.

Disavantages

Currying is not common when we're solving problems. Well, In my case I used it a few times, specifically on Factories.

Our first Currying Function using JavaScript

// No curried function
const sumThreeNumbers = (a, b, c) => (a + b + c);

// You designed a function that always will suon only three numbers.
// But what if I need a sum four numbers? or 'n' numbers?
console.log(sumThreeNumbers(1, 2, 3)); // 6


// Curried
const add = (a) => (function(b) { return a + b} );

// I can sum as I want without depend of the number of arguments.
console.log(add(add(1)(2))(3)); // 6
console.log(add(add(add(1)(2))(3))(4)); // 10
Enter fullscreen mode Exit fullscreen mode

But this code looks a little bit confusing. So, I will improve it, but this time using TypeScript.

Improving our first Currying Function using TypeScript

There are two proposals to improve our first currying function. The first one is cool, but the second one is my favorite.

By saving state

This example looks much like a very similar to the core concept and I don't needed to design a currying function that returns a limited curried functions to sum a exactly 'n' times.

const add = (...a: number[]): Function => {

  function curried(...b: number[]) {
    return add(...a, ...b)
  }

  // Just saving the 'state' to the returned value.
  // Remeber that Functions are objects too in JS.
  curried.done = a.reduce((result: number, value: number) => result + value;

  return curried;
}

// I designed a nice currying sum by saving the state.
console.log(add(1)(2)(3)(4)(5)(6).done); // 21
Enter fullscreen mode Exit fullscreen mode

It works fine, but I have one problem: I'm using a object and I want use only functions. So, here is the second proposal to improve our currying function.

By use recursion

This case designed to use the passed function until it detect there's no more arguments given.

const curryUntilHasNoArguments = (functionToCurry: Function): Function => {
  const next = (...args: any[]) => {
  // I tried to avoid use any[] without spread the var with no success.
    return (_args: any[]) => {
      if (!(_args !== undefined && _args !== null)) {
        return args.reduce((acc, a) => {
          return functionToCurry.call(functionToCurry, acc, a)
        }, 0);
      }
      return next(...args, _args);
    };
  };
  return next();
};


const add = curryUntilHasNoArguments((a: number, b: number) => a + b);
// Don't forget end with '()' to tell that there's no more arguments.
console.log(add(1)(3)(4)(2)());
Enter fullscreen mode Exit fullscreen mode

Real-world example

Finally, I want to finish this article solving a 'real-world' problem (kind of). The sum currying example is trivial and I used it just with demonstrative purposes.

Logger

enum Method {
    WARN = "warn",
    ERROR = "error",
    LOG = "log",
    DEBUG = "debug",
    INFO = "info"
}

function createLogger(name: string, ): Function {
  return function(action: Method){
    return function print(message: string): void {
        console[action](`[${new Date()}] [${name}] ${message}`);
    }
  }
}

const logger = createLogger("Curry");
logger(Method.DEBUG)("This is a debug"); // [Dummy Date][Curry] This is a debug
Enter fullscreen mode Exit fullscreen mode

You could avoid a lot of 'if' by using this kind of logger implementation.

// Dummy scenario
const response = await api.call();
const {metadata, message} = response;

createLogger(api.name)(getMethod(metadata))(message);

function getMethod(metadata: ApiMetadata): Method {
 // do something with the metadata to return a valid Method.
 switch (metadata){
     case metadata.fail: return Method.error; 
 }
}

Enter fullscreen mode Exit fullscreen mode

Resources.

  1. https://javascript.info/currying-partials
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

Top comments (0)