This is a series of articles on currying functions in JavaScript. It consists of an introductory post (this one) and several follow ups that delve into basic and advanced currying with JavaScript.
In the next post, named Basic Curried Functions in JavaScript, we'll see an example of a basic curried function. And in the follow up posts, we'll gradually cover more advanced techniques for currying existing functions.
Before that, first, we'll consider a few underlying terminologies.
Arity
The arity of a function is the number of arguments a function expects at invocation.
Unary Functions
Unary functions are functions that take only one argument, i.e. their arity is one. They are very common in Haskell, where a function can only be unary.
Curried Functions
The simplest form of a curried function is a unary function that returns another unary function. The returned function can also return another unary function. Returning nested unary functions continues in sequence to achieve the results of a multi-argument function. This gives us the ability to call the function with one argument at a time, sequentially.
// Regular multi-argument function
const createMessage = (greeting, name, message) => {
return `${greeting}, ${name}! ${message}`);
};
// A curried function helping achieve the same thing
const createMessage = greeting => name => message => `${greeting}, ${name}! ${message}`);
// So now we can do this:
createMessage('Hello')('World')('Whadup?');
In Haskell, this is the technique used to deliver functions that effectively accept multiple arguments, but one at a time. The word "curry" comes from Haskell Curry.
Higher Order Functions
Curried functions are also Higher Order Functions, or HOFs -- as they always return other functions, and also commonly take in the to-be-curried function.
Variadic Curried Functions
A variadic curried function is a more sophisticated curried function that is able to take variable number of arguments per call. Each returned function may take a single argument, or more than one argument. Basically, we can also do this:
createMessage('Hello', 'World')('Whadup?');
// or
createMessage('Hello')('World', 'Whadup?');
Top comments (17)
In my mind your example is simply the more general concept of partial application.
"The ability to apply only some of a function’s arguments is called partial application."
[Haskell Programming from First Principles, Chapter 5: Types - Partial Application; p.129]
A variadic curry typically requires a superpositioned result, i.e.:
λvc: Variadic Auto-Curried Lambda Calculus
Example:
Currying solves a problem that JavaScript doesn't have:
Haskell Programming from First Principles
Currying versus partial application (with JavaScript code):
How exactly does Haskell implement the said superposition? Does
Function.prototype.bind
do superposition in JS?I think I just got another reason to hate Physics.
I don't know. If we are talking about the same thing, Haskell will automatically perform a partial application if you provide more than one but less than all of the required arguments.
In principle superposition just implies that two results occupy the same space, i.e. a function and a primitive value. In reality that is smoke and mirrors.
sum
simply returns an object that is callable (i.e. a function object) but also makes its primitive value accessible viaObject.prototype.valueOf()
.No, it simply creates a bound function (which is not possible with arrow functions).
Just be careful because the first
this
binding wins:Nice, thanks!
This is wealth of info. It talks about an enclosing context, updated environment.
I suppose in your
sum
, you're creating the said "equally probable environment" with recursion ?I've seen examples using recursion both with and without
Function.prototype.bind
, but kind of wondering how superposition is being dealt with ?Not sure what that means.
It's not really recursion in the sense of "body recursion" but more in the sense of trampolining.
It's all just conceptual.
Basically we are breaking the expected general contract of a function object by monkey patching the instance to shadow the expected implementations of
Object.prototype.valueOf()
andFunction.object.toString()
available on prototype chain.A more honest representation would be:
Stated plainly:
Overly verbose code is hard to read, so is overly terse code. Closures can make code more difficult to understand, as well as multiple levels of higher order functions and lots of people have trouble with recursion. It's practically a tautology that code that is written in a style you are unfamiliar with is harder to read.
If universal readability was the aim we'd probably end up with something as uninspired as Go.
For me it has less to do with my own comfort level but more with Andrea Giammarchi yelling at me in the back of my head to stop creating all this unnecessary garbage for the garbage collector to collect 😉.
In Haskell currying is built in; in JavaScript it could quickly devolve into "premature pessimization".
Perhaps replaceablity should be more important than reusability.
Nice... please tell me more about functions
Ok, another way to create unnecessary overhead :(
BTW the correct ES6 syntax should be :
const createMessage = (greeting, name, message) => {}
and not :
const createMessage(greeting, name, message) => {}
I believe.
It's always been my contention that currying is hogging all the glory when in fact partial application is doing most of the heavy lifting (unless you are actually constrained to lambda calculus).
That said, in most cases plain functions (expressions, really) compose just fine ("Look ma, no closures").
As I said, JavaScript doesn't have the problem that currying solves, as fascinating as currying may be.
And (mutable) closures are great when you need them, just don't go looking for excuses to use them.
*Curried functions
I'm at odds with calling this
a curried function. There is a currying pattern implemented in the function, but it has not been curried from any passed in function. No?
Haskell wiki Currying:
Currying is the process of transforming a function that takes multiple arguments in a tuple as its argument, into a function that takes just a single argument and returns another function which accepts further arguments, one by one, that the original function would receive in the rest of that tuple.
is the curried form of
… In Haskell, all functions are considered curried: That is, all functions in Haskell take just one argument.
Yes, I agree.
Given this notion (or definition, if that is so) of currying, are we able to say the below function is a curried function ?
I think it does not implement currying as a technique - as there is no transformation involved. It very well does implement currying as a pattern, if we can call it a pattern. It's just a JS function declared to return a sequence of unary functions that currying an existing function would do.
I'm talking about semantics, obviously.
I have not been able to find usage of Curry (Haskell's last name, capitalized) as a noun. I think the verb "curry" is more prevalent, takes us to the kitchen. But, for me, it makes sense to attribute the technique to the person Curry, and then derive the verb from Curry, like Curry-ing.
We could call currying a pattern, if that is accepted as so. I'd love to read if there is any historical context.
According to the wiki's usage
is the curried form of the otherwise equivalent
It isn't the result of currying, the transformation by a compiler, runtime or a library function like Rambda's curry. But it is deliberately written in a fashion where only a single argument is accepted and another single argument function is returned until all parameters are bound and the final value is returned.
So while "In JavaScript, all functions are considered curried" is clearly false, it could be argued that
createMessage()
has been crafted to behave in a curried fashion which is close enough for many people to refer to it as a "curried function".The issue is that nobody uses the term "curry function". If you want to be careful you could state that "
createMessage
satisfies the curried form`".Also keep in mind that in lambda calculus the author is forced to write functions in the curried form due to the constraints of lambda calculus, i.e. the author is doing the "currying" manually. So it's not too far of a stretch to state that in lambda calculus all functions have to be "curried" or that it only supports "curried functions".
In JavaScript things are a bit less clear as it doesn't support "currying" as such but it has sufficient capabilities to allow functions to be written in the curried form.
This is really the point I am at.
Currying transformation is not happening at runtime in this example, but while we write our code. As you said earlier, it's conceptual. It's about our design thinking. Then, is currying a design pattern ? Anything concrete about that so far ?
I am aware that nobody uses "curry functions". But, I think it will make a lot of sense if currying is a accepted design pattern, rather than merely as a technique.
Software, Faster • Dan North • GOTO 2016:
"Linda Rising has my favourite description of a pattern, she says if you go up to someone to say 'Hey I've got this pattern and it's a really good idea, let me show you it' and they show you it and you go that's a really good idea then it's not a pattern, it's a really good idea.
OK, if you go up to someone you say 'Hey I've got this pattern and it's like this' and they say I thought everyone did that—then it might be a pattern.
You're naming things that you see."
Dave Thomas:
"They are treated by most developers as recipes: “I need a to implement a xxx pattern”.
But they aren’t. Instead, they are a naming system. Once you’ve written code, you can say “oh, look, that’s like a strategy pattern.” You could then refer to it as such as a short cut when talking with other developers."
[ref]
"Consequently, you'll find recurring patterns of classes and communicating objects in many object-oriented systems. These patterns solve specific design problems and make object-oriented designs more flexible, elegant, and ultimately reusable."
[Design Patterns. Elements of Reusable Object-Oriented Software, 1995; p.1]
"Idioms are low-level patterns specific to a programming language. An idiom describes how to implement particular aspects of components ot the relationships between them with the features of the given language.
In this chapter we provide an overview of the use of idioms, show they can define a programming style, and show where you can find idioms."
[Pattern-Oriented Software Architecture, A System of Patterns, Vol.1 1996; p.345]
In my mind no; at best it's an idiomatic practice within the context of lambda calculus. That said, it's an idiomatic practice with a name.
In terms of JavaScript I'm even reluctant to use the term "curry". Rambda gets away with it because
curry()
"transforms" the passed function by wrapping it inside another function which mimics curried behaviour.Given the capabilities inherent in function expressions (including arrow function expressions),
Function.prototype.apply()
,Function.prototype.bind()
, andFunction.prototype.call()
I think it makes a lot more sense to talk about the practical applications of partial application in JavaScript—but that isn't as "cool" as currying.The issue is in the phrasing of the title.
The segment of the audience who knows what's going on expects to see "Curried Functions in JavaScript", so the title is jarring.
The uninitiated will wonder, "What's a 'curry function'" failing to read it as "Lets curry functions in JavaScript". So the title doesn't really connect with anybody in a meaningful way.
It's good to know that it is idiomatic after all. Related to Haskell Curry, but ironically still idiomatic.
I think I will leave the title as is, because of the depth of the discussion around it.