I am having a hard time understanding a bit of example code from the book JavaScript Allongé (free in the online version).
The example code is a function for calculating the circumference for a given diameter. It shows different ways to bind values with names. One way to go about it, according to the book is this:
(
(diameter) =>
((PI) => diameter * PI)(3.14159265)
)(2);
// calculates circumference given diameter 2
It further states:
Well, the wrinkle with this is that typically, invoking functions is considerably more expensive than evaluating expressions. Every time we invoke the outer function, we’ll invoke the inner function. We could get around this by writing
(
((PI) =>
(diameter) => diameter * PI
)(3.14159265)
)(2);
I cannot understand how it gets around the situation with calling two functions, aren't there exactly two function calls in both the examples? How do they differ from each other?
This probably looks a bit confusing because I don't think it's explained very well. Or, rather, I don't think it's explained in a typical JavaScript way.
Let's break down the examples
var calculateCircumference = (diameter) => (
(PI) => diameter * PI)(3.14159265)
);
calculateCircumference(2); // 6.2831853
Arranged like this, here is what happens if you call this code
PI
as parameter and uses it to calculate the circumference. This function is immediately invoked Aside from being wasteful computation-wise (two invocation) this example is also convoluted for no good reason. The inner function is pointless and doesn't gain you anything. It's probably where the example loses lots of its clarity - seems like the only reason to have the example work as it is, is to set up for the second example.
Before tackling the example, it seems like the book probably failed to mention how exactly it works. The second example leverages a technique called curry
which is used in functional programming - it is not specific to JavaScript but it is still widely known as that name in the JavaScript world. A very brief overview of currying
//non-curried
function add(a, b) { // or, in ES6: (a, b) => a + b;
return a + b;
}
//curried
function curryAdd(a) { //or in ES6: (a) => (b) => a + b;
return function(b) {
return a + b;
}
}
//invocation
add(2, 3); // 5
curryAdd(2)(3); // 5
I will not go into detail but essentially, a curried function that takes multiple parameters, can be passed less and it will return a new function that can take the rest. When all the parameters are satisfied, you will get the result - in a formal notation, the curryAdd
function will be expressed as curryAdd :: Number -> Number -> Number
- it's a function that takes a number and returns another function that takes a number which finally returns another number. For why you would want to do that, here is an example - it's trivial but it gets the point accross:
//add5:: Number -> Number
add5 = curryAdd(5);
add5(3); // 8
add5(10); // 15
[1, 2, 3].map(add5); // [6, 7, 8]
Currying is a bit like partial allocation of functions but the two are not (necessarily) the same thing.
With that said, let's look at the second example:
//curryMultiply :: Float -> Float -> Float
(PI) => (diameter) => diameter * PI
//another way to write it:
//(a) => (b) => a * b
Hopefully that clarifies what is going on a bit. I'll re-write the rest of the example into what is actually happening:
// calculateCircumference :: Float -> Float
var calculateCircumference = curryMultiply(3.14159265);
calculateCircumference(2); //6.2831853
The second example's code is equivalent to the above. It avoids invoking a function twice because the outer function (which I dubbed curryMultiply
) is invoked only once - any time you call the calculateCircumference
function, you are only evaluating the inner function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With