0

我了解 IO 用于将纯代码与不纯代码分开。另外,我知道 IO 允许引用透明性。

不过,关于 IO 的一件事对我来说仍然有点模糊。也就是说,保证 IO 包含的操作之间不会发生任何不好的事情,因为它在调用时立即运行(因为它只不过是一个惰性组合)。所以,当这个惰性组合最终被调用时,没有其他并发代码可以扭曲它(这个惰性组合)。

真的是这样吗?IO 会比这样的一段代码更好(在这种情况下)吗?

var x = 1; //shared resource

//some other code access and changes x to 2

const y = multiplyBy100(x);
const z = add1000(y);

log(z); // 1200 instead of desired 1100

我知道 IO 是解决此类问题的方法。

IO(function () {return x;}).map(multiplyBy100).map(add1000).map(log); //1100 no matter what

我的推理可以吗?

4

1 回答 1

0

您的想法从正确的方向开始,因为 IO 单子确实允许分离不纯和纯动作。我认为当你提到这一点时你遗漏了一些东西

另外,我知道 IO 允许引用透明性。

您可能将 IO 本身的语义与它们为外部代码提供的好处混为一谈。IO 本身并没有太多允许引用透明性,而是允许引用透明(纯)的函数与 IO 中包含的不纯操作进行交互,而不会失去它们的引用透明性。

当您编写一个 IO 操作并运行它时,不能保证结果是引用透明的,而这正是重点。当我们明白 IO 是不纯行为的倾倒地时,这并不奇怪。

所以,当这个惰性组合最终被调用时,没有其他并发代码可以扭曲它(这个惰性组合)。

不幸的是,事情并不是那么简单。懒惰的代码不会使其具有引用透明性。对诸如延迟(延迟)的 IO 之类的函数链的评估与它们正在操作的值无关。

在 javascript 的上下文中,所有值都是引用。堆栈上任何在其范围内具有引用的函数都可以更改所述引用的值。让我向您展示这对于您自己的示例代码意味着什么,该示例代码显示 IO 无论如何都返回 1100 的值。当我在声明 IO 包装 x 之前或之后更改 x 的值时,IO 返回的值将反映这样的变化。因此,此代码不会返回//1100 no matter what,但实际上会返回1200

function switcharoo() {
  x = 2;
}

var x = 1;

var IOdoMaths = IO(() => x).map(x => x * 100).map(x => x + 1000);

// Some concurrent proccess calls this
switcharoo();

var result = IOdoMaths.runIO();

console.log(result); // 1200

我们期待 IO 操作会导致结果1100,但结果却是1200。请记住,当我们创建 IO 时,我们包装了一个引用而不是一个值。这适用于 Javascript 中的任何类型的闭包。声明后是否在 IO 中填充闭包并不重要,相同的规则将适用。

于 2016-07-27T20:35:32.637 回答