我正在读一本用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
方法时,它会调用PrintStream
对象实例上的方法println
,该对象实例在System
类中声明为字段out
(或者更准确地说,在Console
对象中声明为outVar
(,从而更改其内部状态。这可以看作是CCD_ 18是不纯函数的另一种解释。
希望这能有所帮助!
这与引用透明度的概念有关。如果可以在不更改程序的情况下用其求值结果替换表达式,则表达式是引用透明的。
当一个表达式不是引用透明的时,我们说它有副作用。
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