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