如何在 ES6 中柯里化递归函数

How to curry a recursive function in ES6

我正在使用 javascript lambda 表达式进行一些函数式编程练习,并得出以下代码。该代码旨在 return 一个函数,该函数计算给定基值的给定数字的幂。我的代码如下;

const findUpper = base => (num, i = 0) => {
  if (num < base) {
    return i;
  } else {
    i++;
    return findUpper(Math.round(num / base), i);
  }
}

const findUpper2 = findUpper(2)
console.log(findUpper2(8)) //expected to have 3

这里的问题是,递归在第一次 findUpper 调用后就被破坏了,因为它 return 是一个函数。

我怎样才能使这个代码段起作用?

一种方式是这样

    var findUpper = base => {
        let fn = (num, i = 0) => {
            if (num < base) {
                return i;
            } else {
                i++;
                return fn(Math.round(num / base), i);
            }
        };
        return fn;
    }
    var findUpper2 = findUpper(2)
    console.log(findUpper2(8))

在 fundUpper 中声明递归函数...递归调用 fn 而不是 findUpper

稍微"tidier"没有不必要地使用箭头函数

var findUpper = base => {
    return function fn(num, i = 0) {
        if (num < base) {
            return i;
        } else {
            i++;
            return fn(Math.round(num / base), i);
        }
    };
}
var findUpper2 = findUpper(2)
console.log(findUpper2(8))

虽然,使用=>代码可以像

一样简单
const findUpper = base => {
    let fn = (num, i = 0) => (num < base) ? i : fn(Math.round(num / base), i + 1);
    return fn;
}

这是你的错误

i++
return findUpper(Math.round(num / base), i);

您打算:

// don't forget, findUpper is a curried function
return findUpper(Math.round(num/base))(i + 1);

这是将程序编写为纯表达式的另一种方法

const findUpper = (base = 1) => (num = 0, exp = 0) =>
  num < base
    ? exp
    : findUpper (base) (num / base, exp + 1)
    
console.log (findUpper (2) (8))

使用通用 loop/recur 过程,我们保持 findUpper 的参数干净,提高循环性能,并维护您想要的柯里化接口

const recur = (...values) =>
  ({ recur, values })
  
const loop = f =>
{
  let acc = f ()
  while (acc && acc.recur === recur)
    acc = f (...acc.values)
  return acc
}

const findUpper = (base = 1) => (num = 0) =>
  loop ((n = num, exp = 0) =>
    n < base
      ? exp
      : recur (n / base, exp + 1))

console.log (findUpper (2) (8))