我正在阅读Scala中的编程书籍,据说:
...在这种情况下,其副作用是打印到标准输出流。
而且我看不到副作用在哪里,因为对于相同的输入,println会在每次
调用时输出相同的输出(我认为)
UPDATE
,例如:
println(5)
它会打印5,我看不到调用println(5)
将打印5以外的其他值的情况!
println
是确定性函数,但是为了纯净它也必须是RT。
我正在阅读Scala中的编程书籍,据说:
...在这种情况下,其副作用是打印到标准输出流。
而且我看不到副作用在哪里,因为对于相同的输入,println会在每次
调用时输出相同的输出(我认为)
UPDATE
,例如:
println(5)
它会打印5,我看不到调用println(5)
将打印5以外的其他值的情况!
println
是确定性函数,但是为了纯净它也必须是RT。
Answers:
您可以通过将表达式替换为其结果来判断表达式是否有副作用。如果程序改变了含义,那会有副作用。例如,
println(5)
是一个不同的程序
()
也就是说,副作用是在评估表达式的结果中未编码的任何可观察到的效果。结果是()
,但是该值中没有任何东西可以编码5现在已经出现在屏幕上的事实。
val a = println("hello"); val b = (a, a)
应与相同val b = (pritnln("hello"), println("hello"))
。
println(5)
与的区别()
。还是您的意思是最后一句话?
x = 1
和x = 1; x = 1; x = 1
?
考虑以下类比
var out: String = ""
def myprintln(s: String) = {
out += s // this non-local mutation makes me impure
()
}
这myprintln
是不纯净的,因为除了返回值之外,()
它还会将非局部变量out
作为副作用进行突变。现在想象一下out
是流香草println
突变。
()
,它还突变了中的非本地状态System.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
f(println("effect"), println("effect"))
在控制台“效果”中要打印两次,而val x = println("effect");f(x,x)
要打印一次。