编译器能否自动检测纯函数,而不需要关于纯度的types信息?
所以我和我的朋友争辩说,像GCC这样的编译器可以自动检测一个纯函数而没有任何types的信息。 我不信。
像D或Haskell这样的语言在他们的types系统中具有纯度,程序员明确地定义了什么函数是纯粹的。 一个纯函数没有副作用,因此很容易被并行化。
所以问题是:这是否是必要的? 一个编译器是否可以检测到纯度,没有任何元或types的信息,只要假设IO或自动访问全局variables的任何东西都不是纯粹的?
当然,在某些情况下,您可以检测纯function。 例如,
int f(int x) { return x*2; }
可以通过简单的静态分析检测为纯粹的。 难度一般在这样做,检测使用“内部”状态但外部纯净的接口基本上是不可能的。
GCC确实有警告选项 -Wsuggest-attribute=pure
和-Wsuggest-attribute=const
,它们暗示可能是pure
和const
属性的候选对象的const
。 我不确定是否select保守(即缺less许多纯粹的function,但从来没有build议它为非纯function)或让用户决定。
请注意,GCC对pure
的定义是“仅取决于参数和全局variables”:
许多函数除返回值外没有任何影响,它们的返回值仅取决于参数和/或全局variables。 这样的函数可以像算术运算符一样受到常见的子expression式消除和循环优化。 这些函数应该用属性
pure
声明。– GCC手册
严格的纯度,即在所有情况下对于相同的参数都是相同的结果,由const
属性表示,但是这样的函数甚至不能引用传递给它的指针。 所以pure
函数的并行机会是有限的,但相比于你可以使用像Haskell这样的语言编写的纯函数, const
函数可以是更less的函数。
顺便说一下,自动并行纯function并不像你想象的那么容易。 困难的部分变成决定什么并行。 并行计算太便宜了,而开销却使得它毫无意义。 不够平行,而且不能获得好处。 由于这个原因,我不知道有任何实际的function语言实现可以自动并行化,尽pipe像repa这样的库在用户代码中没有显式并行性的情况下在后台并行执行许多操作。
还有另一个问题。 考虑
int isthispure(int i) { if (false) return getchar(); return i + 42; }
该函数实际上是纯粹的,虽然它包含不纯的代码,但是这个代码无法到达。 现在假设false
被g(i)
取代,但是我们知道g(i)是假的(例如,g可能检查它的参数是Lychrel数 )。 为了certificate这个确实是纯粹的,编译器必须certificate不存在Lychrel数字。
(我承认这是一个相当理论上的考虑,也可以决定,如果一个函数包含任何不纯的代码,它本身就是不纯的,但这不是由C型系统恕我直言)。
确定一个函数是否纯粹(即使在GCC所使用的有限的意义上)等价于暂停问题,所以答案是“不适用于任意函数”。 可以自动检测某些函数是纯的,其他函数是纯的,并将其余的标记为“未知”,这在某些情况下允许自动并行化。
根据我的经验,即使程序员也不是很擅长弄清这些事情,所以我希望types系统能够帮助我logging ,而不仅仅是优化器。
我在写一篇比较C#和C ++性能的文章的时候发现,Visual C ++确实可以检测一个中等复杂度的纯函数,同时调用一个计算多项式的函数 。
我在循环中调用多项式函数来消耗时间。 编译器优化了调用,在循环开始之前运行一次,并在循环内重新使用结果。 要做到这一点,就必须知道没有副作用。
我必须说,能够保证编译器可以做一个优化,通过标记一个纯函数,它也可以作为文档的一种forms。