Scala 为什么;“从文件中读取”;这不是纯函数吗?

Scala 为什么;“从文件中读取”;这不是纯函数吗?,scala,functional-programming,Scala,Functional Programming,在《Scala中的函数编程》一书中,给出了几个“副作用”的例子,其中之一是: 读取或写入文件 我可以理解“写入文件”并不纯粹,因为它改变了环境。但为什么“读取文件”不纯粹?这不会改变任何事情 参见我的示例: val readFile: File => String = file => readingTheContentFromFile(file) 对于相同的输入,纯函数总是返回相同的值。否则,它将基于副作用(如更改文件)。 如果从文件中读取,结果可能会更改,而函数的参数不会更改

在《Scala中的函数编程》一书中,给出了几个“副作用”的例子,其中之一是:

  • 读取或写入文件
我可以理解“写入文件”并不纯粹,因为它改变了环境。但为什么“读取文件”不纯粹?这不会改变任何事情

参见我的示例:

val readFile: File => String = file => readingTheContentFromFile(file)

对于相同的输入,纯函数总是返回相同的值。否则,它将基于副作用(如更改文件)。 如果从文件中读取,结果可能会更改,而函数的参数不会更改


相关概念是“参考透明度”。这意味着您可以用函数返回的结果替换函数调用和给定的参数集。因此,从文件中读取不是引用透明的

在函数式编程中,函数是

  • 给定相同的参数值,该函数始终计算相同的结果值。函数结果值不能依赖于任何 程序执行时可能更改的隐藏信息或状态 继续或在程序的不同执行之间执行,也不能 依赖于来自I/O设备的任何外部输入
  • 结果的评估不会导致任何语义上可观察的副作用或输出,例如可变对象或输出的突变 连接到I/O设备
  • 如果

  • 相关I/O设备上的操作序列明确建模为参数和结果,以及
  • 当输入序列没有描述自程序开始以来实际执行的操作时,I/O操作被视为失败 执行

  • 也就是说,不是实际读取文件,而是获取“文件内容”作为参数,而不是实际写入文件,而是返回“文件输出”作为值。在大多数实用语言中,这似乎是一个思考练习。

    如果函数是纯函数,那么执行它总是安全的,即可以替换以下伪代码

    do {
      x = readFile "file.txt"
      writeFile "file.txt" "Goodbye"
      return (x + readFile "file.txt")
    }
    


    你会得到同样的结果。但很明显,由于在第一个示例中,对
    writeFile
    的调用出现在对
    readFile
    的两个调用之间,因此这不是一个安全的转换,因此函数不是纯函数。

    如果对于相同的输入参数,函数给出相同的结果,则函数是纯函数,因此:

    • 函数
      write(file)
      不是纯粹的,因为如果给定相同的
      文件
      ,它可能导致成功或失败

    • 函数
      read(file)
      不是纯粹的函数,因为给定相同的
      文件
      ,它每次都可能返回不同的数据或失败

    因为它们不是纯函数,所以它们不是引用透明的,也就是说,函数调用
    write(file)
    read(file)
    不能被其结果替换,因为下次进行相同调用时,它可能会产生不同的结果

    纯函数的美妙之处在于,如果它们现在成功了,那么您可以确信,如果它们和它们调用的函数此后没有改变,它们将继续成功

    请注意,纯度与改变或不改变环境无关,因为:

    • 每个函数在内部读取和写入计算机内存,并消耗能量,因此每个函数都会改变环境

    • 如果读取和写入同一个文件总是返回相同的结果,那么这些函数将是纯函数,尽管它们会接触环境


    您是否考虑过仅读取文件的一部分如何改变文件的“读取指针”,或者您只关心读取整个文件并假设文件的内容始终相同(这是一个延伸)?可能重复的是,纯函数只能在其参数改变时改变。如果从文件中读取,则该文件可能会独立于函数参数进行更改。
    do {
      x = readFile "file.txt"
      writeFile "file.txt" "Goodbye"
      return (x + x)
    }