【问题标题】:How to tell if an F# function is pure?如何判断 F# 函数是否为纯函数?
【发布时间】:2013-03-30 21:09:51
【问题描述】:

假设我有这两个 F# 函数:

let sq x = x*x

let tm = DateTime.Now

显然 sq 是纯的,因为它对于给定的输入总是返回相同的值,而 tm 是不纯的,因为每次调用它都会返回不同的值。

一般来说,有没有一种方法可以确定 F# 中的特定函数是纯函数还是不纯函数,而无需分析它的作用,换句话说,就是逐行读取它?

或者有没有办法在你写的时候给一个函数注解,告诉编译器这个函数是纯的还是不纯的?

最后,当调用一个属于公共语言运行时(例如 DateTime)的函数时,如何不尝试就判断它是纯的还是不纯的?

注意:“纯”是指来自维基百科的定义:http://en.wikipedia.org/wiki/Pure_function (permalink)

在计算机编程中,如果两个函数都可以描述为纯函数 这些关于函数的陈述成立:

  1. 在给定相同参数的情况下,该函数始终计算相同的结果值 值。函数结果值不能依赖于任何 可能随着程序执行而改变的隐藏信息或状态 进行或在程序的不同执行之间,也不能 依赖于来自 I/O 设备的任何外部输入。

  2. 结果的评估不会导致任何语义上可观察的一面 效果或输出,例如可变对象的突变 或输出到 I/O 设备。

【问题讨论】:

  • 当你说纯,你真的是指幂等吗?还是说没有副作用?
  • 啊,所以维基百科说两者。很公平。 FWIW,我不认为 Microsoft 提供任何类型的注释或属性将功能标记为“纯......”你只需要知道。
  • 这个问题stackoverflow.com/questions/4391524/… 值得一读。

标签: f# pure-function


【解决方案1】:

F# 没有提供任何功能和工具来检查方法是否纯,因此一个简单的答案是您必须自己检查此属性。

在 F# 之外,值得注意的是 Code Contracts 库有一个纯方法的概念(它们可以用 PureAttribute 标记),但我不完全确定那里的检查故事是什么。我认为 Code Contracts 带有分析 IL 的静态检查器(也应该适用于 F#),但这是一项相当艰巨的任务,所以我希望它非常有限。但是,PureAttribute 用于某些 BCL 方法,因此您可以看出某些标准 .NET 方法是纯的。

【讨论】:

  • PureAttribute 只是告诉代码契约该函数是纯函数的一种方式——不执行任何分析(运行时或静态)
  • 不幸的是,代码合同 still doesn't 与 F# 一起使用。
【解决方案2】:

从技术上讲,您的 'tm' 值不是一个函数,而是 DateTime 类型的值,并且它是不可变的,因此每次在创建此值后评估它总是相同的。

【讨论】:

  • ...为了进一步澄清,如果你说 let tm() = DateTime.Now (注意添加括号)你会强制它成为一个可能是你意图的函数。
【解决方案3】:

鉴于可以在 f# 中定义纯函数和非纯函数,如果有一种算法可以检查 f# 代码(函数定义)的纯度,我会感到非常惊讶——检查程序代码的语义属性通常是赖斯定理无法判定。

【讨论】:

  • NimHaxe 确实做到了这一点,并且在命令式和函数式编程中都深谙此道,所以这是可能的。
  • 他们是在某些情况下还是在所有情况下都这样做?
  • Nim 在几周前添加了最后剩余的边缘案例覆盖范围。我不知道 Haxe。
  • 线程启动器希望能够“确定 F# 中的特定函数是纯函数还是不纯函数”。据我了解,Nim 验证了一些纯函数实际上是纯函数。但是,我知道 threadstarter 需要一个过程,给定 any 函数决定手头的函数是否是纯函数。特别是,如果一个函数与一个全局可变变量交互但最终没有改变它,这个(取决于你对纯粹性的定义)应该被认为是一个纯函数——我仍然认为这是不可能的.
  • 是的,这可能是真的。尽管如此,F# 不能做一个,也不能做另一个,并且评论说,这在某些支持命令式设计的语言中根本不可能,是不正确的。
猜你喜欢
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 2018-04-13
  • 1970-01-01
相关资源
最近更新 更多