我正在阅读 scala 编程的书,据说:
...在这种情况下,它的副作用是打印到标准输出流。
而且我看不出副作用在哪里,因为对于相同的输入, println 将打印相同的输出(我认为)
例如任何时候我们调用
更新:
println(5)
它会打印5,我没有看到调用println(5)
会打印 5 以外的值的情况!
我正在阅读 scala 编程的书,据说:
...在这种情况下,它的副作用是打印到标准输出流。
而且我看不出副作用在哪里,因为对于相同的输入, println 将打印相同的输出(我认为)
例如任何时候我们调用
更新:
println(5)
它会打印5,我没有看到调用println(5)
会打印 5 以外的值的情况!
您可以通过将表达式替换为其结果来判断表达式是否具有副作用。如果程序改变了含义,就会产生副作用。例如,
println(5)
是一个不同的程序
()
也就是说,副作用是未编码在评估表达式的结果中的任何可观察到的效果。这里的结果是()
,但该值中没有任何内容可以编码 5 现在出现在屏幕上的某处这一事实。
副作用是在计算机的状态。每次调用println()
内存状态时都会发生变化,以便向终端显示给定值。或者更一般地说,标准输出流的状态发生了变化。
考虑以下类比
var out: String = ""
def myprintln(s: String) = {
out += s // this non-local mutation makes me impure
()
}
这myprintln
是不纯的,因为除了返回值之外()
,它还会改变非局部变量out
作为副作用。现在想象out
成为流香草println
变异。
这个问题已经给出了很好的答案,但让我加两分钱。
如果你看一下println
函数内部,它本质上是一样的java.lang.System.out.println()
——所以当你在后台调用 Scala 的标准库println
方法时,它会调用对象实例println
上的方法,该方法在类中(或更准确地说是在对象中)PrintStream
声明为字段,这会改变它的内部状态. 这可以被认为是另一种解释为什么是不纯函数。out
System
outVar
Console
println
希望这可以帮助!
它与引用透明度的概念有关。如果您可以在不更改程序的情况下将其替换为计算结果,则表达式是引用透明的。
当一个表达式不是引用透明时,我们说它有副作用。
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