是的。它保证是纯净的。
原因是它只依赖于绑定和不可变的自由变量。
但是,这段代码打破了访问外部函数的范围的规则,即 范围。
你的报价中没有什么说你不能访问自由变量。它说外部输入是从文件,网络等中读取的,而不是来自先前范围的自由变量。
即使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
这是纯粹的。封闭变量/自由变量f1
,f2
,initialValue
从不改变创建的功能。 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
,你会说这不是纯粹的。这与someMethod
和obj
也是如此。
您可以制作适用于大型数据结构的功能类,这意味着您在进行回溯拼图解算器时无需在更改之前将其复制。一个简单的例子是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);
lst0
是lst
但与前面的新元素。 lst0
重复使用lst
中的所有内容。从列表到二叉树的所有内容都可以用这种方法制作,并且可以使用不可变的二叉树制作许多连续的数据结构。它从50年代开始就一直存在。
请注意,纯函数也经常与其他函数有依赖关系,只要这些其他函数是纯的,依赖函数也被认为是纯粹的。我看不出你的例子与此不同。所以是的,'timesTen'是一个纯粹的功能。尽管你不能保证引用透明度。因此,说你可以确信你的功能是纯粹的,这可能会更合适。 – ftor
我完全同意你@ftor!就语言而言,请忽略它。我的问题是关于概念,而不是实际上用某种特定的语言可以实现什么概念。 – thiagoh
@thiagoh当然,如果它的所有依赖都是纯粹的,那么函数仍然是纯粹的 - 这是ftor所说的内容,我同意他100%。 – naomik