【问题标题】:How to enhance purity of function if we are using closures如果我们使用闭包,如何提高函数的纯度
【发布时间】:2021-11-14 05:38:45
【问题描述】:

我有一个伪函数如下

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 规则,两个函数在每次执行时都没有给出相同的输出,所以我很好奇如何在给定用例的情况下增强代码?

【问题讨论】:

  • 这个问题对我来说没有意义。您想通过使用函数状态来避免全局变量,并且您想要一个通过闭包具有状态的纯函数。这甚至意味着什么?纯函数没有状态。
  • 对于像你这样的函数,它基本上是一个生成器,“纯度”并不是一个真正相关的概念。
  • 只要是要写入文件系统的动作,反正都是不纯的,因为有副作用...不是吗,那么,不管有没有依赖于可变状态?
  • 最纯粹的,但无论如何最直观的方法是将计数器作为参数传递给 ... function createNewFile(counterValue) { /* ... */ } ... 像 ... createNewFile(counter); .. . 因此程序的另一部分负责counter 的管理以及如何与createNewFile 一起使用。

标签: javascript functional-programming closures


【解决方案1】:

您的函数涉及两个效果:

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

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

I/O 效应更难处理。在 Javascript 中,I/O 通常是异步的,因此 Promise 用于对此类计算进行编码。不幸的是,从功能的角度来看,promise 具有相当无原则的语义,因此我将使用原始延续类型来展示如何在后台延迟 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);

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-13
    • 2014-08-05
    • 2017-01-17
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    相关资源
    最近更新 更多