如果我们使用闭包,如何提高函数的纯度

How to enhance purity of function if we are using closures

我有一个伪函数如下

let counter = 0;

function createNewFile() {
  const fileName = `book_${counter++}`;

  //...write file or whatever
};

上面的函数createNewFile绝对不理想,因为它依赖于外部变量counter,可能会意外改变。我正在考虑通过如下所示的闭包和 IIFE 来减少这种情况发生的可能性

const counter = (() => {
  let counter = 0;
  return () => counter++;
})();

console.log(counter())
console.log(counter())

/*
function createNewFile() {
  const fileName = `book_${counter()}`;

  //...write file or whatever
};
*/

上面的代码达到了现在 counter 可以说是“更难”被“意外”更改的目的。

但是,我想知道从函数式编程的角度来看,我们如何才能同时改进函数 countercreateNewFile?因为显然都违反了 pure function 规则,两个函数在每次执行时都不会给出相同的输出,我很好奇如何在给定用例的情况下增强代码?

您的函数与两个效果有关:

  • 依赖局部变量的变异
  • I/O 通过写入文件系统

您可以通过将局部变量作为参数传递来简单地避免局部变量。状态被移动到调用堆栈。但是,您无法使用此技术避免所有突变。出于这个原因,函数式编程通常提供持久数据结构,这是一种巧妙的不变性形式。

I/O 效果更难处理。在 Javascript 中,I/O 通常是异步的,因此 promises 用于对此类计算进行编码。不幸的是,从功能角度来看,promises 具有相当无原则的语义,因此我将使用原始延续类型来展示如何在幕后延迟 I/O 效果:

function createNewFile(counter, data) {
  const fileName = `book_${counter}`;
  return k => {run: k(writeFile(fileName, data))}
};

const description = createNewFile(1, someData);

description.run(checkSuccess);

我们没有执行效果,只是取回了对这个动作的描述。该功能本身并不是特别有用。我们需要将其结果应用于其他纯函数或将其与其他描述结合而不实际执行效果的方法,但这将超出此答案的范围。