New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uncurrying #3713
Comments
I suspect this simply never came up as an important thing to look at, indeed because normal JavaScript doesn't produce code like this. Can you share what the optimization algorithm you propose would look like? How would you identify the function expressions, and when to inline their contents? |
My thinking so far is that whenever there is an uninterrupted sequence of successive function f(x){
return function(y){
return ...;
}
} If the call site is Also consider that when uncurrying a function I've implemented this in a Haskell-like-to-JS compiler in the past (Fay) and found that increased code size pre-Closure, but decreased code size post-Closure pass. It's also a bit faster and less liable to stack overflow. In particular, type-class generic functions implicitly by the compiler are provided an argument for each class instance (this avoids doing vlookups). Naturally, the larger the call chain, the more argument passing we're doing. With curried functions, that's a lot of nested PureScript like Haskell generates impure code only within a module boundary, so there's a lot of mileage out of such rewrites. Please let me know if you think this is something that could be practically added to Closure or whether you think it'd be unlikely to make it in. |
We'll discuss this and get back to you. |
Some notes:
|
Thanks for the update @lauraharker. 😄 🎉 I added some thoughts below as concerns that PS programmers have, and why I think they'll be covered already if we follow straight-forward rules. Nullary functionsI know this may be obvious, especially to the Closure Compiler maintainers, but I'll note it anyway: PureScript uses function print(s){
return function(){
console.log(s);
}
} then these are strung together via when(x>5,then(print("hi"),then(print("world"),pure(123))) and the Removing the intermediate Of course, following "only reduce it if fully saturated" would not remove such nullary functions anyway. Verdict: no problem. Intermediate resultsOthers in the PS community have pointed out e.g. function func(x){
let thing = bigCalculation(x);
return function(y){
return go(y)(thing);
}
} The motivation being that you might use
As this sequence is interrupted by In other words, it's a concern PS programmers have, but it wouldn't come up anyway based on this thread. Verdict: no problem. |
Unfortunately, given the body of code Closure is generally used on and the technical cost of this idea, we don't have any plans to implement it in the near future. |
Thanks for the update @nreid260; I appreciate the frankness and quick turn around on this reply. Pleasure interacting with the team. It was worth asking. I may take a shot at it sometime in Haskell as a basic rename-and-then-uncurry step. But don’t let that stop anyone else trying; my time budget is presently allocated elsewhere! |
Tried setting On commit 2809700, diff:
Command:
Input:
Output:
|
Thanks a bunch @krk, that's a highly encouraging tip! I'll try it. |
😞 I'm not able to reproduce your result @krk with this Dockerfile https://gist.github.com/chrisdone/52124977ff5b6833558544f977423f0c and your patch on commit I made a docker image with that Dockerfile and ran
and then
The output is:
Any idea what's different between your and my setup? |
@chrisdone, I have created a Dockerfile that demonstrates the patch at https://gist.github.com/krk/01355fedc9df9dd639498e23b6fa0380
|
Thanks a bunch @krk! I’ve eyeballed the Dockerfile and can’t see where my attempt diverged from yours, but no matter, I’m sure it was something subtle and trivial. Happy new year! 🎊 EDIT: I was able to reproduce the result. ✔️ |
Hi @chrisdone, I am also a PureScript user looking for better handling on minification. Glad to see this thread that enables me to reuse the same findings with @krk. There is an NPM package that I just published for easy usage: |
I have packaged up @sd-yip's NPM package into a Nix Flake, which can be found here: https://github.com/jeslie0/closure-compiler-acocr. Hopefully, this is useful to anyone that finds this thread. |
One thing that functional languages like PureScript do is generate curried functions. This appears to be a blocker for Closure. For example,
Closure outputs,
Excellent result. It did pretty straight-forward transformations here. Including removing the overhead of generic functions, which are achieved via dictionary (argument) passing in Haskell-like languages. However, in languages like Haskell/PureScript, functions are all single-argument chains of functions, like this:
Unfortunately, Closure outputs the following:
This means that PureScript's output is both large and slow -- this example is small, but imagine large codebases with nested levels of this.
So it seems that "uncurrying" is not a process that Closure currently does. I'm not sure whether this was decided against, simply because it's not normal in JS to have functions like this, or whether it's an oversight, or whether there's a good reason that makes reducing these in the general case difficult.
Could someone fill me in?
If it's simply not something considered, how difficult would it be to add? Is it something I could implement myself in Closure? I'm discussing with the PureScript community and considering whether to add it to the compiler output, but on the other hand,
this kind of thing feels like Closure's bread and butter, so I'm attempting to do it the Right Way before going off and patching something further up the chain.
The text was updated successfully, but these errors were encountered: