为什么这个纯函数的实现不被认为具有外部依赖性?

smi*_*oli 7 javascript functional-programming pure-function

我很喜欢这个pure function概念很简单的例子,比如...

function addTwo(val){
   return val + 2;
}
Run Code Online (Sandbox Code Playgroud)

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

但后来我遇到过这样的例子(取自弗里斯教授大多数指导,但我在其他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) {
  ...
};
Run Code Online (Sandbox Code Playgroud)

我不明白为什么不被认为是外部依赖(因此,不纯)对saveUser或的调用welcomeUser.

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

我很难理解为什么

function multiplyBy(times){
  return value => value * times;
}
const fiveTimes = multiplyBy(5);
fiveTimes(10);
Run Code Online (Sandbox Code Playgroud)

被认为pure.从返回的函数POV,访问times是对范围链的查找,它可以来自直接的外部范围,或来自更远的范围(如全局范围).

有谁愿意为此带来一些启示?

Kyl*_*son 17

我对JavaScript中函数纯度的解释是,没有二进制"纯粹"或"不纯"这样的东西,而是函数可预测的一种信心.例如,通过传递带有副作用吸气剂的物体,可以使用各种技巧来制作看似纯粹的功能.

因此,一旦我们意识到纯度是关于信心的程度,我们就可以问,我对某些功能的行为方式有多么自信?如果该函数引用另一个函数,那么另一个函数是否纯粹有多确定?此外,您是否确定引用其他功能的标识符不会/无法重新分配以指向您不知道的其他功能?

我亲自编写我的程序代码,以便我几乎不会重新定义指向函数的标识符,特别是如果声明了该函数而不仅仅是函数表达式.通过这种方式,我感到非常自信(比方说,99.99%)如果foo(..)打电话bar(..),我确信它bar(..)是可靠的纯净,那么foo(..)也是可靠的纯净,因为我知道我不会重新分配bar(..)任何其他功能并导致令人惊讶的结果.

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

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

但同样重要的是,JS中的函数纯度大约是置信水平,而不是绝对的二元是或否.

  • 我认为*置信水平*是一段代码作者和读者之间松散的契约.作者可以或多或少地提高合同的有效性,从而为读者带来或多或少的可读性. (2认同)

dec*_*eze 5

纯函数的定义是:

一个函数,它总是在给定相同参数值的情况下评估相同的结果值,并且不会导致任何语义上可观察到的副作用或输出,例如可变对象的变异或输出到I/O设备.

"有依赖性"在定义纯函数时绝对没有任何作用.唯一重要的是该功能是否有任何副作用,其结果是否取决于外部状态.如果函数的行为完全相同并且在给定相同输入的情况下始终产生相同的结果,则它是纯粹的.如果一个函数有任何副作用(修改全局状态)或根据外部状态的不同行为,它是不纯的.函数可能依赖于(读取:调用)另一个函数作为其操作的一部分; 只要其他功能也是纯净的,那就不会污染纯度.

signUp您显示的示例是纯粹的,因为它仅作用于其输入,并且在使用相同输入调用时始终返回完全相同的输出.请注意,函数本身不会"执行"任何操作.它不会调用数据库或产生任何副作用.它所做的就是返回一个函数.但是如果输入相同,则返回的函数总是相同的.返回的功能实际上是不纯的; 但产生它的功能不是.