计算函数是否纯函数


11

根据维基百科:

在计算机编程中,如果关于函数的以下两个语句均成立,则函数可以描述为纯函数:在给定相同的参数值的情况下,函数始终求值相同的结果值。函数结果值不能依赖于任何隐藏的信息或状态,这些信息或状态可能随着程序执行的进行或程序的不同执行之间的变化而变化,也不能依赖于I / O设备的任何外部输入。结果评估不会引起任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I / O设备。

我想知道是否有可能编写一个可以计算一个函数是否纯净的函数。JavaScript中的示例代码:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False

7
这可能是计算机科学堆栈交换的候选人。这更倾向于理论领域(“可能的”),而不是实践和设计领域……这有点超出我的范围。

...即使它是“可能的”和“理论的”,也很可能对此有一个真正的答案(非常适合问答),甚至可能包含一个证明……这又将其带回了计算机科学领域。

我认为您可以通过查看在其定义中调用的函数的类型来确定函数是否是纯函数。我的意思是,您可以通过归纳功能结构来定义纯度。
乔治

7
没有特定于平台的反射黑客是不可能的。如果函数是黑匣子,则没有实验可以证明它是纯函数。例如,如果存在类似的问题if (rand(1000000)<2) return WRONG_ANSWER,那么多次对函数进行探查以获取一致的行为将无济于事。但是,如果您可以访问函数定义,则证明是微不足道的。
SK-logic

1
@ user470365从纯函数定义开始 -“结果的评估不会引起任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I / O设备。” -根据定义,写入IO的任何内容都是不纯的。在此示例中,不纯净的say呼叫console.log也是不say纯净的。

Answers:


17

是的,有可能,具体取决于语言。

在JavaScript中,可以通过以下条件判断函数是否纯净:

  • 它只读取参数和局部变量;

  • 它只写本地人。

  • 在非本地上,它仅调用纯函数。

  • 它隐式调用的所有函数都是纯函数,例如toString;和

  • 如果本地人没有别名非本地人,则仅写入本地人的属性。

通常,无法在JavaScript中确定别名,因为您始终可以动态地查找对象的属性(object["property"])。如果您从不这样做,并且您拥有整个程序的源代码,那么我认为问题是可以解决的。您还需要有关哪些本机函数具有副作用的信息,例如console.log涉及DOM的大多数东西。

“纯”一词也可以作一些说明。即使在所有函数都引用透明的强静态类型纯函数编程语言中,函数仍然可能无法终止。因此,当我们谈论时id :: a -> a,我们真正要说的不是:

给定一些type值a,该函数将id产生type值a

反而:

给定类型的一些值a,该函数id不会产生一个值,该值类型的a

由于有效的执行id就是error "Not implemented!"。正如彼得斯(Peteris)指出的那样,这种不完全可以被视为一种杂质。Koka是一种功能性编程语言,其语法基于JavaScript建模,可以推断出可能的影响,例如分歧(非终止),参照透明性,引发异常和I / O操作。


+1-鉴于Peteris的回答,因此获得了很多好评.....
mattnz 2012年

我想您需要在条件列表中添加“仅调用纯函数”。
格雷格·休吉尔

1
@GregHewgill:好收获。我相应地更新了答案。只要在局部变量上没有副作用,就可以在局部变量上调用变异函数。“纯”这个词太过分了…
乔恩·普迪

您还需要检查toString用作字符串的任何对象是否纯。
Oleg V. Volkov,2012年

我认为这个答案是不正确的,因为只有少数情况可以真正做出这些决定。考虑:此函数是纯函数吗?function a (o) { return o.method(); }-我们实际上不能回答这个问题,因为它取决于o传递的参数。此外,如果将先前认证的纯函数更改为非纯实现,那么我们将无法解释会发生什么,这始终是javascript的潜在问题。
朱尔斯

11

否。您可以轻松地检查函数是否仅执行“纯安全”操作,如Jon Purdy的回答所述,但这仅是IMO,不足以回答问题。

考虑以下功能:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

显然,如果someCheck不纯,也是如此possiblyPure。但是,如果someCheck是纯粹的,返回true的每一个可能值xpossiblyPure是纯粹的,因为unpure代码路径不可达!

困难的部分就来了:确定someCheck每个可能的输入是否返回true。试图立即回答该问题会使您进入停顿问题和类似的不确定问题的境界。

编辑:证明这是不可能的

无论是否必须在每个可能的输入上终止纯函数,都存在一些不确定性。但是在两种情况下,暂停问题都可以用来表明纯净度检查是不可能的。

情况A)如果要求纯函数在每个可能的输入上终止,必须解决暂停问题,以确定该函数是否为纯函数。由于已知这是不可能的,因此根据此定义,无法计算纯度。

情况B)如果允许纯函数不终止于某些输入,我们可以构造类似的东西:假设isPure(f)计算if f是一个定义纯函数的字符串。

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

现在isPure必须确定是否f暂停其自身的输入源。如果停止,upf则不纯净;如果不终止,upf则为纯,如果f为纯。

如果isPure按预期工作(返回正确的结果并在每次输入时终止),我们将解决停止问题(*)!由于已知这是不可能的,isPure因此不存在。

(*)用于纯JavaScript函数,这也足以解决图灵机的问题。


3
真正。总是可以进行保守分析-检查某个函数是否绝对纯,但无法检查它是否绝对不纯。
SK-logic

许多情况是微不足道的-Jon Purdy描述的那些纯函数或无条件地做一些肮脏的事情的纯函数;但总的来说,人们可以构造无法确定的案例。
user281377 2012年

1

这个stackoverflow问题有一个与yfeldblum相关的答案。(由于某种原因,我无法接受低级投票。对已使用了3年的东西进行高级投票是否有礼节?)

我认为从实用的角度来看,如果让函数返回“是”,“否”或“也许”,对于某些语言而言,这并不难。几天前,我正在观看有关Clojure的视频,演讲者通过搜索大约4个不同的字符串(例如“ ref”)对一个代码库中的杂质实例进行了计数。由于Clojure强调纯净和不纯物质的隔离,所以它是微不足道的,但它并不是您想要的。

因此,如果您稍微调整一下问题,从理论上讲是不可能的,在实践上是可能的,我认为这将有多困难很大程度上取决于语言。专注于不变性和良好反射的简单/简洁语言将更容易。


我认为,它被否决了,因为它是错误的。bottom是有效的头等舱值,因此不应以这种方式加以区别。
SK-logic

0

好问题。

假设没有能力尽可能多地听取I / O动作来调用函数的信息,那么您在实践中将做的最好。然后查看返回值是否一致。

但是您通常不能这样做。可以说,非停止程序不是纯粹的程序,我们无法确定停止问题。


1
-1:编写通过此测试的函数绝非易事。
mattnz

3
按照这种逻辑,任何void函数都是“纯”的,这显然是错误的。
格雷格·休吉尔

1
@Greg:通过扩展,void foo(void)也必须是纯净的。
mattnz

0

在一般情况下是不可能的。请参阅停止问题。简而言之,编写具有任意功能和输入即可确定该程序将永远停止还是运行的程序是不可能的。如果它永远运行,那么它就不是一个完全符合您定义的纯函数


5
永远运行似乎并不会因为满足他的纯函数标准而降低其功能。
whatsisname 2012年

1:有一个隐含的要求由functiuon终止“功能总是计算相同的结果值给予....”
mattnz

2
持续不断地运行而不修改任何状态是完全“纯粹的”。但是,当然,这是一个术语问题。
SK逻辑

@mattnz,此类函数将始终求bottom值。
SK逻辑

1
我可以看到术语问题的来历。在某些解释中,“纯”函数是确定性的,并且在执行过程中从不与外部传递任何状态或值。在其他解释中,暂停被添加到需求中。通过第一种解释,很容易确定功能是否纯净:执行特定语言的机器应该能够确定该语言的程序是否与外界进行了任何通信。
rwong 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.