10

我正在阅读 scala 编程的书,据说:

...在这种情况下,它的副作用是打印到标准输出流。

而且我看不出副作用在哪里,因为对于相同的输入, println 将打印相同的输出(我认为) 例如任何时候我们调用
更新:

println(5)

它会打印5,我没有看到调用println(5)会打印 5 以外的值的情况!

4

5 回答 5

8

您可以通过将表达式替换为其结果来判断表达式是否具有副作用。如果程序改变了含义,就会产生副作用。例如,

println(5)

是一个不同的程序

()

也就是说,副作用是未编码在评估表达式的结果中的任何可观察到的效果。这里的结果是(),但该值中没有任何内容可以编码 5 现在出现在屏幕上的某处这一事实。

于 2020-02-25T21:21:22.750 回答
6

副作用是在计算机的状态。每次调用println()内存状态时都会发生变化,以便向终端显示给定值。或者更一般地说,标准输出流的状态发生了变化。

于 2020-02-25T21:23:47.830 回答
6

考虑以下类比

var out: String = ""
def myprintln(s: String) = {
  out += s // this non-local mutation makes me impure
  ()
}

myprintln是不纯的,因为除了返回值之外(),它还会改变非局部变量out作为副作用。现在想象out成为流香草println变异。

于 2020-02-25T21:35:54.850 回答
2

这个问题已经给出了很好的答案,但让我加两分钱。

如果你看一下println函数内部,它本质上是一样的java.lang.System.out.println()——所以当你在后台调用 Scala 的标准库println方法时,它会调用对象实例println上的方法,该方法在类中(或更准确地说是在对象中)PrintStream声明为字段,这会改变它的内部状态. 这可以被认为是另一种解释为什么是不纯函数。outSystemoutVarConsoleprintln

希望这可以帮助!

于 2020-02-26T09:32:20.483 回答
2

它与引用透明度的概念有关。如果您可以在不更改程序的情况下将其替换为计算结果,则表达式是引用透明的。

当一个表达式不是引用透明时,我们说它有副作用

f(println("effect"), println("effect"))
// isn't really equivalent to!
val x = println("effect")
f(x, x)

尽管

import cats.effect.IO

def printlnIO(line: String): IO[Unit] = IO(println(line))

f(printlnIO("effect"), printlnIO("effect"))
// is equivalent to
val x = printlnIO("effect")
f(x, x)

你可以在这里找到更详细的解释:https ://typelevel.org/blog/2017/05/02/io-monad-for-cats.html

于 2020-02-26T15:11:09.690 回答