Skip to content
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

Handmade optimizations? #5

Open
PEZO19 opened this issue May 14, 2022 · 4 comments
Open

Handmade optimizations? #5

PEZO19 opened this issue May 14, 2022 · 4 comments

Comments

@PEZO19
Copy link

PEZO19 commented May 14, 2022

@staltz

Hi there! I am not sure how useful this is or how useful it ever can be, but while studying callbags I realized that both the theoretical protocol (using 0,1,2 numbers extensively) and the exact operator implementations (via neat and succinct callbacks) make room together for handmade optimizations. (We used to do such things as homework at the uni, so I know that for many this literally can be fun, I feel that the callbag abstraction truly enables that by its nature.)

I am wondering if that can be useful at scale (more operators) and what kind of performance tests or other things could be created to be really useful - and of course what shall be the target ES version...

I just want to put here an example how I progressed with that (I know some tricks, but I am not a pro in that area), maybe some folks will think it further.

I think we might find quite a lot patterns across operators. A few notes / examples / interesting things:

  • omitting return
  • reusing the original start variable
  • removing both skipped and talkback variables
  • merging control flows via order swap (2 sink calls instead 3, unfortunately lost the "bad" example)
  • tricks around 0

The right side of the assignment went from
102 chars: t=>e=>(i,n)=>{if(0!==i)return;let r,s=0;e(0,(e,i)=>{0===e?(r=i,n(e,i)):1===e&&s<t?(s++,r(1)):n(e,i)})}
to
74 chars: i=>s=>(t,c)=>{!t&&(s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i--?t(1):c(s,f)}))}
-27% :)

Tests passed, however I realized that omitting the first conditional (originally the return part) won't make tests fail, I tried to keep that there though.

I used this minifier as a starter: https://skalman.github.io/UglifyJS-online/

// this is a close, "reverted" version from the last one at the bottom (`skipA`)
const skip = max => source => (start_then_Talkback, sink) => {
  if (!start_then_Talkback) {
    // let skipped = 0;
    // let talkback;
    source(0, (t, d) => {
      if (t == 1) {
        if (0 < max--) {
          start_then_Talkback(1);
        }
        else sink(t, d);
      }
      else if (t == 0) {
        start_then_Talkback = d;
        sink(t, d); // c(s,f) below
      }
      else {
        sink(t, d);
      }
    });
  };
}

// NOTE COMMENTS ON THE RIGHT >>>>>

const skip1=t=>e=>(i,n)=>{if(0!==i)return;let r,s=0;e(0,(e,i)=>{0===e?(r=i,n(e,i)):1===e&&s<t?(s++,r(1)):n(e,i)})}; // baseline
const skip2=i=>s=>(t,c)=>{if(0===t){let t,e=0;s(0,(s,f)=>{0===s?(t=f,c(s,f)):1===s&&e<i?(e++,t(1)):c(s,f)})}}; // omit `return`
const skip3=i=>s=>(t,c)=>{if(0==t){let t,e=0;s(0,(s,f)=>{0==s?(t=f,c(s,f)):1==s&&e<i?(e++,t(1)):c(s,f)})}};    // double == instead ===
const skip4=i=>s=>(t,c)=>{if(!t){let t,e=0;s(0,(s,f)=>{0==s?(t=f,c(s,f)):1==s&&e<i?(e++,t(1)):c(s,f)})}};      // !t instead 0==t
const skip5=i=>s=>(t,c)=>{if(!t){let t,e=0;s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&e<i?(e++,t(1)):c(s,f)})}};        // !s instead 0==s
const skip6=i=>s=>(t,c)=>{if(!t){let t;s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i?(i--,t(1)):c(s,f)})}};            // remove `skipped` variable (decrement until 0 instead increment to max)
const skip7=i=>s=>(t,c)=>{if(!t){let t;s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i--?t(1):c(s,f)})}};                // glueing `i?(i--...` to `i--(...`
const skip8=i=>s=>(t,c)=>{if(!t){s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i--?t(1):c(s,f)})}};                      // reuse `start` variable in inner scopes as it is only used once "far out"
const skip9=i=>s=>(t,c)=>{if(!t)(s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i--?t(1):c(s,f)}))};                      // () instead {} to make it more `expression` friendly
const skipA=i=>s=>(t,c)=>{!t&&(s(0,(s,f)=>{!s?(t=f,c(s,f)):1==s&&0<i--?t(1):c(s,f)}))};                        // `!t&&` instead `if(!t)`
@staltz
Copy link
Owner

staltz commented May 14, 2022

Cool code golfing! I would accept some PRs for this, as long as we don't do minification of variable names by hand. i.e. keep names as they were and code formatting/indentation as well.

@PEZO19
Copy link
Author

PEZO19 commented May 14, 2022

@staltz Okay! I'll do that! :) Would you prefer to see the evolution of the code step by step in a branch or you're only interested in the end result? Also: are you ok with omitting variables? (Reusing a variable for multiple "purposes" if context makes that possible.)

@PEZO19
Copy link
Author

PEZO19 commented May 15, 2022

@staltz This one? Shall I change index.js or make a new file?

const skip = max => source => (start, sink) => {
  !start &&
    (source(0, (t, d) => {
      !t ? (
        start = d,
        sink(t, d)
      ) :
      t == 1 &&
        0 < max-- ?
          start(1) :
      sink(t, d)
  }))
};

@staltz
Copy link
Owner

staltz commented May 17, 2022

@PEZO19 I'd like to at least keep the ifs, unless they are a leaf if.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants