IO monad中包含的组合函数是否保证没有不期望的效果?

时间:2016-06-15 09:02:52

标签: javascript side-effects io-monad

我知道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

我的推理好吗?

1 个答案:

答案 0 :(得分:0)

你的思维从正确的方向开始,因为IO monads允许分离不纯和纯粹的行为。当你提到

时,我认为你错过了一些东西
  

另外,我知道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中填充闭包并不重要,则适用相同的规则。