在“Scala中的函数编程”一书中,它给出了几个“副作用”的例子,其中之一是:
我能理解“写入文件”并不纯粹,因为它会改变环境。但为什么“读文件”并不纯粹?它没有改变任何东西。
参见我的例子:
val readFile: File => String = file => readingTheContentFromFile(file)
答案 0 :(得分:13)
纯函数allways在给定相同输入的情况下返回相同的值。否则它基于副作用(如更改文件)。 如果从文件中读取,结果可能会更改,而不会更改函数的参数。
相关概念是“参考透明度”。这意味着您可以使用函数返回的结果替换函数调用和给定的参数集。因此,从文件中读取不是参考透明的!
答案 1 :(得分:6)
如果函数是纯函数,那么执行common subexpression elimination总是安全的,即你可以替换下面的伪代码
do {
x = readFile "file.txt"
writeFile "file.txt" "Goodbye"
return (x + readFile "file.txt")
}
与
do {
x = readFile "file.txt"
writeFile "file.txt" "Goodbye"
return (x + x)
}
你会得到相同的结果。但很明显,由于在第一个示例中对writeFile
的两次调用之间出现readFile
的调用,这不是一个安全的转换,因此函数不是纯粹的。
答案 2 :(得分:2)
在函数式编程中,如果
,函数为pure
- 在给定相同参数值的情况下,函数始终评估相同的结果值。功能结果值不能依赖于任何 程序执行时可能发生变化的隐藏信息或状态 继续或在程序的不同执行之间,也不可能 取决于I / O设备的任何外部输入。
- 评估结果不会导致任何语义上可观察到的副作用或输出,例如可变对象或输出的突变 到I / O设备。
醇>
I/O can be modelled in a pure way if
- 相关I / O设备上的操作序列被明确建模为参数和结果,并且
- 当输入序列没有描述自程序开始以来实际采取的操作时,I / O操作失败 执行。
醇>
也就是说,不是实际读取文件,而是将“文件的内容”作为参数,而不是实际写入文件,而是将“文件的输出”作为值返回。这似乎是大多数实用语言的思想练习。
答案 3 :(得分:0)
如果函数针对相同的输入参数给出相同的结果,则它是纯函数,因此:
函数write(file)
并不纯,因为给定相同的file
可能导致成功或失败。
函数read(file)
并不纯,因为给定相同的file
,每次返回或失败都会返回不同的数据。
由于它们不是纯净的,因此它们不是引用透明的,也就是说,函数调用write(file)
或read(file)
不能用其结果代替,因为下次进行相同的调用时,它可以产生不同的结果。
纯函数的美妙之处在于,如果它们现在成功,那么您可以确信,如果它们及其调用的函数此后没有发生变化,它们将继续成功。
请注意,纯度与更改或不更改环境无关,因为:
每个函数在内部读写计算机内存,并消耗能量,因此每个函数都会改变环境;
如果读写同一文件总是返回相同的结果,那么尽管这些函数会接触环境,但这些函数将是纯函数。