为什么不认为纯函数的实现具有外部依赖关系



我对pure function的概念很满意,比如…

function addTwo(val){
   return val + 2;
}

给定相同的参数,它产生相同的结果,导致引用透明度和良好的确定性代码。

但是后来我遇到了这样的例子(取自教授frisby的大部分足够的指导,但我在其他FP JS书籍中发现了类似的例子)

//pure
var signUp = function(Db, Email, attrs) {
  return function() {
    var user = saveUser(Db, attrs);
    welcomeUser(Email, user);
  };
};
var saveUser = function(Db, attrs) {
  ...
};
var welcomeUser = function(Email, user) {
  ...
};

和我不明白为什么不考虑外部依赖(所以,不纯)调用saveUserwelcomeUser

我知道,从函数/IO的角度来看,signUp总是返回"相同"(等效)有线函数,但我感觉很奇怪。

我很难理解为什么

function multiplyBy(times){
  return value => value * times;
}
const fiveTimes = multiplyBy(5);
fiveTimes(10);

被认为是pure。从返回的函数POV中,对times的访问是对作用域链的查找,它可以来自直接的外部作用域,也可以来自外部作用域(如全局作用域)。

有谁想给这个带来一些光明吗?

我对JavaScript中函数纯度的解释是,没有所谓的二元"纯"或"不纯",而是函数行为可预测的信心范围。有各种各样的技巧可以使一个函数看起来不是纯粹的,例如,通过传递一个带有副作用getter的对象。

因此,一旦我们意识到纯度是关于信心程度的,我们就可以问,我对某个函数会按照我期望的方式运行有多大的信心?如果这个函数引用了另一个函数,你有多确定另一个函数是纯函数?此外,你有多确定引用其他函数的标识符不会/不能被重新分配给指向其他你不知道的函数?

我个人编写程序时,几乎从不重新定义指向函数的标识符,特别是如果该函数是声明的,而不仅仅是函数表达式。这样,如果foo(..)调用bar(..),并且我确信bar(..)是可靠纯的,那么foo(..)也是可靠纯的,因为我知道我不会将bar(..)重新赋值给任何其他函数,从而导致令人惊讶的结果。

有些人甚至用const fn = function ..来定义他们的函数标识符。我不认为这有多大帮助……这可能会使我的信心水平从99.99%提高到99.999%。在我看来,这并不足以证明它的使用是合理的。

此外,关于你的问题的闭包部分:如果一个内部函数关闭了一个仍然包含在纯函数中的外部变量,并且没有重新分配该变量,那么它实际上是一个常数,所以我对可预测性的信心水平非常高。

但是,在JS中,函数的纯度是关于信心水平的,而不是绝对的二进制是或否。

纯函数的定义:

给定相同的参数值,总是计算相同的结果值,并且不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I/O设备的函数。

"有依赖关系"在定义纯函数时绝对没有作用。唯一重要的是函数是否有任何副作用以及它的结果是否依赖于外部状态。如果一个函数的行为完全相同,并且在给定相同的输入时总是产生相同的结果,则它是纯函数。如果一个函数有任何副作用(修改全局状态),或者根据外部状态表现不同,那么它就是不纯的。一个函数可能依赖于(read: call)另一个函数作为其操作的一部分;只要另一个函数也是纯函数,就不会影响它的纯度。

您所展示的signUp示例是纯粹的,因为它只对其输入起作用,并且在使用相同的输入调用时总是返回完全相同的输出。注意,函数本身并没有"做"任何事情。它不会调用数据库,也不会产生任何副作用。它所做的只是返回一个函数。但是如果输入相同,返回的函数总是相同的。返回的函数实际上是不纯的;但是产生它的函数不是。

相关内容

  • 没有找到相关文章

最新更新