为什么未来有副作用?

zer*_*ing 10 functional-programming scala

我正在阅读FPiS一书,在第107页上,作者说:

我们应该注意到Future没有纯粹的功能界面.这就是为什么我们不希望我们图书馆的用户直接处理Future的部分原因.但重要的是,即使Future上的方法依赖于副作用,我们的整个Par API仍然是纯粹的.只有在用户调用run并且实现接收到我们公开Future机制的ExecutorService之后.因此,我们的用户可以编程为纯粹的界面,但其实现仍然依赖于当天结束时的效果.但由于我们的API仍然纯净,这些效果不是副作用.

为什么Future还没有纯粹的功能界面?

Luk*_*itz 20

问题在于,由于Future的渴望本质,创造一个引起副作用的未来本身也是副作用.

这打破了参考透明度.即如果你创建一个只打印到控制台的Future,将来会立即运行并运行副作用而不需要它.

一个例子:

for {
  x <- Future { println("Foo") }
  y <- Future { println("Foo") }
} yield ()
Run Code Online (Sandbox Code Playgroud)

这导致"Foo"被打印两次.现在,如果Future引用透明,我们应该能够在下面的非内联版本中获得相同的结果:

val printFuture = Future { println("Foo") }

for {
  x <- printFuture
  y <- printFuture
} yield ()
Run Code Online (Sandbox Code Playgroud)

然而,这只是打印"Foo"一次,甚至更多的问题,它打印它无论你是否包括for-expression.

使用引用透明表达式,我们应该能够在不改变程序语义的情况下内联任何表达式,Future不能保证这一点,因此它会破坏引用透明性并且本质上是有效的.

  • 我看不出这是如何针对未来的。执行函数的表达式不是真的吗?如果给它一个有副作用的lambda,它会产生副作用...(Duh!):)就像...我不知道...`Seq(1,2,3).filter {println _ ; true}`也会使`Seq`不完全起作用吗? (2认同)
  • 是的,确实如此!功能编程就是将副作用推向程序的边缘!:)看看这篇文章:http://typelevel.org/blog/2017/05/02/io-monad-for-cats.html (2认同)

jwv*_*wvh 9

FP的基本前提是参考透明度.换句话说,避免副作用.

有什么副作用?来自维基百科:

在计算机科学中,如果函数或表达式修改了其范围之外的某些状态或者与其调用函数或外部世界具有可观察的交互,则称其具有副作用.(除非按惯例,返回一个值:返回一个值会对调用函数产生影响,但这通常不被视为副作用.)

什么是Scala未来?从文档页面:

Future是一个可能尚不存在的值的占位符对象.

因此,未来可以从尚未存在的价值转变为现有价值而不与程序的其他部分进行任何交互,并且正如您所引用的那样:"未来的方法依赖于副作用."

似乎Scala期货不保持参考透明度.


P. *_*lov 5

据我所知,Future在创建时会自动运行计算.即使它在嵌套计算中缺乏副作用,它仍然会破坏flatMap组合规则,因为它随时间改变状态:

someFuture.flatMap(Future(_)) == someFuture // can be false
Run Code Online (Sandbox Code Playgroud)

除了平等实施问题,我们可以在这里遇到一个竞争条件:新的Future立即运行一小部分时间,并且它isCompleted可以与someFuture已经完成的情况不同.

为了它代表纯洁WRT效果,Future应按照其计算和运行它,只有当用户明确地要求它,就像在的情况下Par(或scalazTask).