【发布时间】:2021-01-24 15:32:41
【问题描述】:
我和this one 有同样的问题,但在 JavaScript 的上下文中。
来自Wikipedia:
[一个纯函数的]返回值对于 same 参数是相同的
那里进一步声称,纯函数不允许使用“可变引用参数”来改变返回值。在 JavaScript 中,每个普通对象都作为“可变引用参数”传递。考虑以下示例:
const f = (arr) => arr.length
const x = []
console.log( f(x) ) // 0
x.push(1);
console.log( f(x) ) // 1
以上证明f不纯吗?
或者你会争辩说我们在这两种情况下没有用“相同”的参数调用f?
我可以看到在执行f 时其他线程可能与可变引用参数混淆的语言/环境中调用不纯的f 是多么有意义。但是由于f 不是async,所以这种情况是不可能发生的。 x 从调用 f 的那一刻到完成执行时将保持不变。 (如果我理解正确,这种解释似乎得到了Verifiable Functional Purity in Java § 4.1 中提出的“相同”定义的支持。)
或者我错过了什么? JavaScript 中是否有一个示例,其中不包含异步代码的函数会丢失 referential transparency 的属性,仅仅是因为它采用可变引用,但如果我们使用例如取而代之的是 Immutable.js 数据结构?
【问题讨论】:
-
在 Javascript 中,对象通过它们的引用获得身份。这种引用身份属性与纯功能语言中的引用透明性相反。如此正式地,Javascript 中没有纯函数,但您可以通过约定和信心获得所需的行为。
-
来自论文:“对于这些问题,没有一个明显正确的答案。因此,确定性是一个参数化的属性:给定参数等价的含义的定义,如果所有带有等效参数的调用返回的结果与该语言内无法区分,则该方法是确定性的”。
-
识别纯函数的原因之一是删除对它们的不必要调用或重新排序代码。您必须考虑两个
x不同,才能将函数视为纯函数。如果这就是分析仪所做的,那很好。但如果没有这个上下文,这个函数就不是纯粹的。 -
所以这不是见仁见智吗?该论文本身表明,对等的定义是一种选择(在一定范围内)。那你是在问一个选择吗?我想这会导致固执己见的答案。
-
Redux 开发人员会认为
f = () => []是“纯”的,即使f() === f()是假的,因为[] === []是假的。因此,您绝对必须在您将如何使用它们的上下文中定义事物等价的含义。还要考虑如果您只是将突变作为属性获取器烘焙会发生什么:x = { get length() { return global++; } }然后,通过预先将global设置为1,f(x) == f(x)很容易为假。所以arr => arr.length和g => g()一样纯粹
标签: javascript function functional-programming purely-functional