const _ = Symbol('placeholder');

function partialWithPlaceholders(fn, ...presetArgs) {
  return function (...laterArgs) {
    let args = [];
    let laterIdx = 0;
    for (let i = 0; i < presetArgs.length; ++i) {
      if (presetArgs[i] === _) {
        args.push(laterArgs[laterIdx++]);
      } else {
        args.push(presetArgs[i]);
      }
    }
    // For variadic tail arguments, add any extras
    while (laterIdx < laterArgs.length) {
      args.push(laterArgs[laterIdx++]);
    }
    return fn(...args);
  };
}

// Example function with regular and variadic parameters
function foo(a, b, ...rest) {
  // e.g., want the 2nd variadic argument
  return rest[1];
}

// Partial application: fix a = 1, b = _, ...rest = 2, 3, _
const part = partialWithPlaceholders(foo, 1, _, 2, 3, _);

// Now call with one more argument, fills the remaining placeholder:
console.log(part(99)); // Output: 3

// You can also use it to fix different arguments:
const part2 = partialWithPlaceholders(foo, _, 10, 20, 30, 40);
console.log(part2(7)); // Output: 30 (rest=[20,30,40], rest[1]=30)

