ARTICLE AD BOX
Functional programming languages like Haskell or OCaml go though some effort to make curried functions have reasonable performance compared to uncurried functions. I am curious if V8 has any optimizations specially for curried functions.
Does V8 optimize direct calls?
Consider the example shown below. Here addFourCurry and addFourUncurry are both called directly. Assuming that they're not inlined, do both of their calls generate the same or at least similar machine code? Does currying change whether either example is inlined?
What can I expect in general of directly calling curried functions?
const example = [1, 2, 3]; const addFourCurry = a => b => c => d => console.log(a + b + c + d); const addFourUncurried = (a, b, c, d) => console.log(a + b + c + d); for (let i = 0; i < example.length; i++) { let e = example[i]; addFourCurry(e)(e)(e)(e); } for (let i = 0; i < example.length; i++) { let e = example[i]; addFourUncurried(e, e, e, e); }Does V8 optimize indirect calls?
Consider the second example below. Here foreachFourCurry necessarily has to be slower because it's calling a function with an unknown arity. However, as is discussed in Making a Fast Curry. The number of arguments can be known at runtime and this allows the stack to be adjusted accordingly. Is the arity of a function tracked and used for saturated calls?
What can I expect in general of indirectly calling curried functions?
const example = [1, 2, 3]; const addFourCurry = a => b => c => d => console.log(a + b + c + d); const addFourUncurried = (a, b, c, d) => console.log(a + b + c + d); function foreachFourCurry(f, list) { for (let i = 0; i < list.length; i++) { let e = list[i]; f(e)(e)(e)(e); } } function foreachFourUncurry(f, list) { for (let i = 0; i < list.length; i++) { let e = list[i]; f(e, e, e, e); } } foreachFourCurry(addFourCurry, example); foreachFourUncurry(addFourUncurried, example);