7

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) {
  ...
};

而且我不明白为什么不将对saveUseror的调用视为外部依赖项(因此,不纯) welcomeUser

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

我很难理解为什么

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

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

有人想为这件事带来一些启示吗?

4

2 回答 2

17

我对 JavaScript 中函数纯度的解释是,没有二进制“纯”或“不纯”之类的东西,而是对函数将按可预测行为表现的信心范围。例如,通过传递一个带有副作用 getter 的对象,可以使用各种技巧来制作一个看起来不纯粹的函数。

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

我个人对我的程序进行了编码,因此我几乎从不重新定义指向函数的标识符,特别是如果声明了该函数而不仅仅是一个函数表达式。这样,我非常有信心(比如说,99.99%)如果foo(..)调用bar(..),并且我确信它bar(..)是可靠纯的,那么foo(..)也是可靠纯的,因为我知道我不会重新分配bar(..)给任何其他函数并导致令人惊讶的结果.

有些人甚至用const fn = function ... 我不认为这有多大帮助……这可能会使我的信心水平从 99.99% 提高到 99.999%。IMO,这并不足以证明其使用的合理性。

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

但同样,JS 中的函数纯度是关于置信度的,而不是绝对的二进制是或否。

于 2016-10-03T15:18:20.080 回答
6

纯函数的定义是:

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

“具有依赖关系”在定义纯函数时绝对没有任何作用。唯一重要的是该函数是否有任何副作用以及其结果是否取决于外部状态。如果一个函数的行为完全相同,并且在给定相同输入的情况下总是产生相同的结果,那么它就是纯函数。如果一个函数有任何副作用(修改全局状态)或根据外部状态表现不同,那么它就是不纯的。作为其操作的一部分,一个函数可能依赖(读取:调用)另一个函数;只要其他功能也是纯的,就不会污染纯洁。

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

于 2016-10-03T15:04:36.680 回答