替换为什么能够成立

若表达式的结果只由明确的输入决定,求值也没有额外可观察效果,那么保存结果后复用它,与在相同条件下重新计算,可以得到相同的程序含义。例如,用已确定的 2 + 3 的值替换该表达式,不应改变后续计算。

反之,读取变化中的外部状态、修改共享变量或发送输出,会使“只看返回值”的替换失去依据。同一函数的两次调用偶然得到相同数字,仍不足以证明它引用透明。

参考:[1]

等式推理与求值策略

引用透明性让程序员可以围绕表达式等式推导结果,而不必同时追踪隐蔽的赋值历史。Haskell 将表达式解释为有静态类型的值,并采用非严格语义,但具体如何编译或解释仍由实现决定。

这不意味着任何计算都可以随意提前执行:发散、错误以及语言对严格性的规定仍影响合法变换。引用透明性提供推理条件,不会单独保证所有函数终止或所有优化都正确。

参考:[2]

值与执行动作要分开

Haskell 的 IO 类型把动作作为可以组合的值表示,区分“描述一个动作”和“执行这个动作”。输入输出的先后由动作的组合明确规定,不能因为表达式层面是纯的,就把两次执行合并成一次。

因此,纯函数式程序仍可以读文件、等待输入或产生输出。关键是效果如何进入程序语义,以及替换保持了什么;引用透明性不是宣称真实世界没有变化。

参考:[3]