【问题标题】:Why "reading from a file" is not pure function?为什么“从文件中读取”不是纯函数?
【发布时间】:2015-07-13 07:32:22
【问题描述】:

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

  • 读取或写入文件

我可以理解“写入文件”并不纯粹,因为它改变了环境。但为什么“读文件”不纯呢?它不会改变任何东西。

看我的例子:

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

【问题讨论】:

标签: scala functional-programming


【解决方案1】:

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

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

【讨论】:

  • 是的,纯函数只有在参数改变时才能改变。如果它从一个文件中读取,该文件可能会独立于函数参数而改变。
【解决方案2】:

如果一个函数是纯函数,那么执行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)
}

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

【讨论】:

    【解决方案3】:

    在函数式编程中,函数是pure if

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

    I/O can be modelled in a pure way如果

    1. 相关 I/O 设备上的操作序列被显式建模为参数和结果,并且
    2. 当输入序列未描述自程序开始后实际执行的操作时,I/O 操作将失败 执行。

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

    【讨论】:

      【解决方案4】:

      一个函数是纯的,如果对于相同的输入参数它给出相同的结果,所以:

      • 函数write(file) 不是纯函数,因为在给定相同的file 时,它可能导致成功或失败。

      • 函数read(file) 不是纯函数,因为在给定相同的file 的情况下,它每次都可能返回不同的数据或失败。

      因为它们不是纯的,所以它们不是引用透明的,也就是说,一个函数调用write(file)read(file)不能被它的结果替换,因为下一次同样的调用它会产生不同的结果.

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

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

      • 每个函数内部都对计算机内存进行读写,并且消耗能量,所以每个函数都会改变环境;

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-09
        • 2022-10-12
        • 1970-01-01
        • 1970-01-01
        • 2012-08-08
        • 1970-01-01
        • 2014-07-21
        相关资源
        最近更新 更多