Curry in JavaScript
Implementation of curring in JavaScript

Curry in JavaScript

Curry function and Currying

Functional programming is super popular when I was an iOS developer five years ago. Currying may be the most mentioned concept at that time.

Currying is not hard to understand: a process which transforms a function that takes multiple parameters into a sequence of functions that each has only a single argument. The concept came from the Haskell programming language, which is a purely functional programming language.

The code below shows how currying works:

// a simple add function
function addTwo(a, b) {
  return a + b;
}

// what do we want our curry function to do?
const curriedAddTwo = curry(addTwo);
curriedAddTwo(1)(2); // 3

A specific implement for addTwo

// A simple and special implement
function curryForAddTwo(addFn) {
  return function (a) {
    return function (b) {
      return addFn(a, b);
    };
  };
}

const curriedAddTwo = curryForAddTwo(addTwo);
curriedAddTwo(3)(4); // 7 doing correct

A more advanced and generate function for curry

A point is using func.length to get the number of func’s arguments. And we’ve already know that arguments in JavaScript function is an array.

// A more general implement
function curry(func) {
  return function curried(...args) {
    // using func.length to get the amount of func's arguments
    if (args.length >= func.length) {
      // means args has enough for func's execution, then execute func.
      return func.apply(this, args);
    } else {
      // if the args is not enough, generate a new function to get another single param
      // using recursive
      return function curryingFunc(...newArgs) {
        const totalArgs = args.concat(newArgs);
        return curried.apply(this, totalArgs);
      };
    }
  };
}

Curry in Swift?

I clearly remember the implementation of curry in Swift programming language is super interesting.

These codes are copied from Curry/Curry.swift at main ยท thoughtbot/Curry (github.com)

public func curry<A, B>(_ function: @escaping (A) -> B) -> (A) -> B {
    return { (a: A) -> B in function(a) }
}

public func curry<A, B, C>(_ function: @escaping ((A, B)) -> C) -> (A) -> (B) -> C {
    return { (a: A) -> (B) -> C in { (b: B) -> C in function((a, b)) } }
}

public func curry<A, B, C, D>(_ function: @escaping ((A, B, C)) -> D) -> (A) -> (B) -> (C) -> D {
    return { (a: A) -> (B) -> (C) -> D in { (b: B) -> (C) -> D in { (c: C) -> D in function((a, b, c)) } } }
}

public func curry<A, B, C, D, E>(_ function: @escaping ((A, B, C, D)) -> E) -> (A) -> (B) -> (C) -> (D) -> E {
    return { (a: A) -> (B) -> (C) -> (D) -> E in { (b: B) -> (C) -> (D) -> E in { (c: C) -> (D) -> E in { (d: D) -> E in function((a, b, c, d)) } } } }
}

public func curry<A, B, C, D, E, F>(_ function: @escaping ((A, B, C, D, E)) -> F) -> (A) -> (B) -> (C) -> (D) -> (E) -> F {
    return { (a: A) -> (B) -> (C) -> (D) -> (E) -> F in { (b: B) -> (C) -> (D) -> (E) -> F in { (c: C) -> (D) -> (E) -> F in { (d: D) -> (E) -> F in { (e: E) -> F in function((a, b, c, d, e)) } } } } }
}

public func curry<A, B, C, D, E, F, G>(_ function: @escaping ((A, B, C, D, E, F)) -> G) -> (A) -> (B) -> (C) -> (D) -> (E) -> (F) -> G {
    return { (a: A) -> (B) -> (C) -> (D) -> (E) -> (F) -> G in { (b: B) -> (C) -> (D) -> (E) -> (F) -> G in { (c: C) -> (D) -> (E) -> (F) -> G in { (d: D) -> (E) -> (F) -> G in { (e: E) -> (F) -> G in { (f: F) -> G in function((a, b, c, d, e, f)) } } } } } }
}

What did you find after reading these codes? Yes, they have to repeatedly write the same code for different parameter numbers. This is because Swift is a static typing and strong typing programming language. They must define every type occurring in the function with generics: <A, B, C, D, E, F, G>. And they cannot get the numbers of parameters like JavaScript’s args.length as well. What a pity! But strong typing brings more advantages than its inconvenient.

Currying in Rust?

Rust is another of my favourite programming language. I’m just wondering: how to implement a curry in Rust?

fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn curry_add(x: i32) -> impl Fn(i32) -> i32 {
    move |num| num + x
}

I can write this simple curry function for add, but I can’t write a more general solution. So, just Google!

This repo gave an example but I’m not sure how many situations it could work.

AlienKevin/curry-macro: Have fun currying using Rust’s native closure syntax (github.com)

#[macro_export]
macro_rules! curry (
   // Simplest form, without any type annotations.
    (|$first_arg:ident $(, $arg:ident )*| $function_body:expr) => {
       move |$first_arg| $(move |$arg|)* {
          $function_body
       }
    };
    // With input type annotations
    (|$first_arg:ident:$first_arg_type:ty $(, $arg:ident:$arg_type:ty )*| $function_body:expr) => {
      move |$first_arg:$first_arg_type| $(move |$arg:$arg_type|)* {
         $function_body
      }
   };
   // With input and return type annotations and a block as function body
   (|$first_arg:ident:$first_arg_type:ty $(, $arg:ident:$arg_type:ty )*| -> $ret_type:ty $function_body:block) => {
    move |$first_arg:$first_arg_type| $(move |$arg:$arg_type|)* -> $ret_type {
       $function_body
    };
   };
);

What are the benefits of currying?

There are a lot of discussions about what are the benefits of currying. I conclude some of the points:

  • More readable
  • Pure function: one input and one output
  • Giving a function fewer arguments than it expects is typically called partial application. Partially applying a function can remove a lot of boilerplate code.

Reference:

[JavaScript Currying (w3docs.com)](https://www.w3docs.com/learn-javascript/currying.html#:~:text=In JavaScript%2C currying represents a transform%2C which turns,needed. Getting partials is also easy with currying.)

functional programming - What is the advantage of currying? - Software Engineering Stack Exchange


Last modified on 2022-01-10