Curried 函数:如何优化它们

Curried functions: how to optimize them

我对函数式编程和库(例如 ramda.js 比较陌生,但我发现非常有用的一件事是柯里化函数的可能性。

使用柯里化函数,我经常写如下内容

const myFun = R.curry(
  (arg1, arg2) => {
    let calculated = anotherFun(arg1)
      //do something with calculated and arg2
    return calculated * 5 + arg2
  }
)

const anotherFun = (arg) => {
  console.log("calling anotherFun");
  return arg + 1
}

var partial = myFun(1)

console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>

但显然在这种情况下,每次我调用 partial 时都会调用 anotherFun,即使在 arg1 中也是如此,因此 calculated 始终相同。

有没有办法优化此行为并仅在其参数更改时调用 anotherFun

我唯一想到的就是这个

const myFun = R.curry(
  (calculated, arg2) => {
    return calculated * 5 + arg2
  }
)

const anotherFun = (arg) => {
  console.log("calling anotherFun");
  return arg + 1
}

var calculated = anotherFun(1)
var partial = myFun(calculated)

console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>

但是这样我必须更改传递给 myFun 的参数,这会使外部 API

如果你像这样手动进行柯里化

const myFun = arg1 => arg2 => {
  let calculated = anotherFun(arg1)
  // do something with calculated and arg2
  return calculated * 5 + arg2
};

你也可以这样优化:

const myFun = arg1 => {
  let calculated = anotherFun(arg1);
  return arg2 => {
    // do something with calculated and arg2
    return calculated * 5 + arg2
  };
};

我认为 Ramda 不会在这里帮助您任何事情; JavaScript 编译器肯定不会进行这种优化。

@Bergi 是的,Ramda 不会为此提供任何帮助。如果你想要一个 Ramda 风格的结果,你可以用一个参数调用来获取一个函数,或者同时调用两个参数来获取结果,你可以这样做:

const myFun = function(arg1, arg2) {
  let calculated = anotherFun(arg1);
  const newFunc = arg2 => {
    return calculated * 5 + arg2
  };
  return (arguments.length < 2) ? newFunc : newFunc(arg2);
};

const with3 = myFun(3);
//: calling anotherFun

with3(1); //=> 21
with3(2); //=> 22
with3(4); //=> 23


myFun(2, 7);
//: calling anotherFun
//=> 22 

myFun(2, 8);
//: calling anotherFun
//=> 23 

这是以无法使用 ES2015 箭头函数为代价的。但这对你来说可能是值得的。

如果提供了两个参数,您也可以稍微修改一下以不构建内部函数,如果这对您很重要的话。

Ramda 的 useWithmemoize 怎么样?

const myFun = R.useWith(
  (a, b) => a * 5 + b,
  [R.memoize(anotherFun), R.identity]
);