Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // trampoline : (thunk -> thunk | value) -> value
- // Runs a chain of thunks iteratively so recursion doesn't grow the JS call stack.
- // - Start with a "thunk" (a function with no args)
- // - While the result is still a function, keep calling it
- // - When a non-function value is produced, return it
- const trampoline = (thunk) => {
- let t = thunk;
- while (typeof t === "function") t = t(); // keep "bouncing"
- return t; // final value
- };
- // foldl : (f, acc, xs, k) -> ...
- //
- // Fold an array xs from left to right in a continuation-passing style (CPS) and
- // use trampoline to stay stack-safe.
- //
- // Type-ish comments:
- // - f : (x, acc, k2) => ...
- // where k2 : (newAcc) => ... is a continuation that tells foldl what to do next
- // IMPORTANT: f is expected to call k2(newAcc) rather than directly returning newAcc.
- // - k : (finalAcc) => ... is the final continuation invoked at the end.
- //
- // Returns: a call that eventually triggers k(finalAcc).
- const foldl = (f, acc, xs, k) => {
- // step(i, accNow) describes "the rest of the fold" starting at index i
- // and current accumulator accNow.
- //
- // It returns either:
- // - a thunk (function) that when called computes the next step, or
- // - in the base case, a thunk that calls k(accNow).
- const step = (i, accNow) => {
- // Base case: we've processed every element in xs.
- if (i >= xs.length) return () => k(accNow);
- // Process the next element.
- const x = xs[i];
- // We don't call f(x, accNow, ...) immediately on the call stack.
- // Instead, we return a thunk so trampoline can manage the iteration safely.
- return () =>
- // Call f in CPS form:
- // f decides how to compute/update the accumulator, and then calls k2(newAcc).
- f(x, accNow, (newAcc) => {
- // After f computes newAcc, continue folding from i+1.
- // step(i + 1, newAcc) returns a thunk, which trampoline will eventually run.
- return step(i + 1, newAcc);
- });
- };
- // Start the fold at index 0 with the initial accumulator acc.
- // step(0, acc) returns the initial thunk; trampoline runs it to completion.
- return trampoline(() => step(0, acc));
- };
Advertisement