这可以被认为是一个纯函数(函数式编程)吗?



我一直在阅读函数式编程及其概念。我很清楚,在大型项目中工作时,您总是需要(在适当的水平上(混合多种范式,例如OO和功能。理论上,函数纯度等概念过于严格,例如

给定相同的参数值,该函数始终计算相同的结果值。函数结果值不能依赖于在程序执行过程中或在程序的不同执行之间可能更改的任何隐藏信息或状态,也不能依赖于来自 I/O 设备的任何外部输入。(https://en.wikipedia.org/wiki/Pure_function(

也就是说,这个(或可以被认为是(代码是一个纯函数吗?

const externalVar = 10;
function timesTen(value) {
return externalVar * value;
}

我问这个是因为,在这种情况下,timesTen函数将始终为输入返回相同的值,任何人都可以更改externalVar的值,因为这是一个常量。但是,此代码破坏了访问外部函数作用域的规则。

是的。保证是纯净的。

原因是它只依赖于绑定和不可变的自由变量。

但是,此代码破坏了访问外部函数的规则 范围。

您的报价中没有任何内容说您无法访问自由变量。它表示外部输入是从文件、网络等读取的,而不是来自先前范围的自由变量。

甚至Haskell也使用全局函数名称,如foldr,它是每个函数中的自由变量,当然结果是纯粹的。

请记住,名称函数只是变量。parseInt是一个指向函数的变量,因此,如果您应该在另一个函数中使用的每个函数都作为参数传递,则很难制作任何东西。

如果您将parseInt重新定义为非纯的东西或在程序持续时间内,以便它的工作方式不同,那么调用它的函数都不会是纯的。

函数组合和部分求值之所以有效,是因为它们提供了自由变量。它是函数式编程中必不可少的抽象方法。例如。

function compose(f2, f1) {
return (...args) => f2(f1(...args));
}
function makeAdder(initialValue) {
return v => v + initialValue;
}
const add11 = compose(makeAdder(10), makeAdder(1));
add11(5); // ==> 16

这是纯粹的。闭包变量/自由变量f1f2initialValue永远不会改变所创建的函数。add11是一个纯函数。

现在再看compose。它看起来很纯净,但可能会受到污染。如果传递给它的两个函数不是纯函数,那么结果也不是。

OO也可以是纯粹的功能!

通过不改变您创建的对象,可以轻松地将它们组合在一起。

class FunctionalNumber {
constructor(value) {
this.value = value;
}
add(fn) {
return new FunctionalNumber(this.value + fn.value);
}
sub(fn) {
return new FunctionalNumber(this.value - fn.value);
}        
}

此类是纯函数式的。

实际上,您可以将像obj.someMethod(arg1, arg2)这样的方法调用视为函数调用,obj作为第一个参数someFunction(obj, arg1, arg2)。这只是语法上的差异,如果someFunction变异obj你会说它不纯粹。someMethodobj也是如此。

您可以创建适用于功能庞大的数据结构的类,这意味着在执行回溯解谜器时,在更改之前永远不必复制它。一个简单的例子是Haskell和Lisp中的对。以下是在 JavaScript 中实现它的一种方法:

class Cons {
constructor(car, cdr) {
this.car = car;
this.cdr = cdr;
}
}
const lst = new Cons(1, new Cons(2, new Cons(3, null)));
const lst0 = new Cons(0, lst);

lst0lst,但前面有一个新的元素。lst0重用lst中的所有内容。从列表到二叉树的所有内容都可以用它制作,你可以用不可变的二叉树制作许多连续的数据结构。它自 50 年代以来一直存在。

我理解您的意见并完全同意@Sylwester,但有一点值得一提:使用反射,可以修改外部常量值并破坏函数的纯度。我们知道IT中的所有内容都可能被黑客入侵,我们不应该考虑这些概念,但在实践中我们应该清楚地记住这一点,即以这种方式,功能纯粹是不合理的。

最新更新