curryN

/**
 * @name curryN
 * @function
 * @since v0.1.0
 * @category Function
 * @sig Number -> ((a, b) -> c) -> a -> b -> c
 * @description Acts like curry but this one expects you to tell it how many arguments to expect
 * this allows it to work well with rest parameters and default params.
 * @param {Number} n The number of arguments the function is expecting
 * @param {Function} f The function we are going to be running with said arguments
 * @param {Any} args The arguments to apply to said function curry wont execute until this length matches n
 * @return {Any} Returns based on the results of the function passed in
 * @example
 * import { curryN } from 'kyanite'
 *
 * const add = curryN(2, (a, b) => a + b)
 *
 * add(1)(2) // => 3
 * add(1, 2) // => 3
 *
 * const sum = add(1)
 *
 * sum(2) // => 3
 * sum(4) // => 5
 *
 * const add2 = curryN(2, (a, b = 1) => a + b)
 * const sum1 = add(1)
 *
 * sum1(4) // => 5
 * sum1(undefined) // => 2
 *
 * // Possible gotcha
 * const foo = curryN(2, (a, b) => a)
 *
 * foo(1)() // => [Function]
 * const bar = foo(1)
 *
 * bar() // => [Function]
 * bar(null) // => 1
 */
const curryN = (n, f, ...args) => {
  if (n <= 0) {
    return f(...args)
  }

  return (...rest) => curryN(n - rest.length, f, ...args, ...rest)
}

export default curryN