javascript 调用 Math.random() 的函数是纯函数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47035166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is a function that calls Math.random() pure?
提问by Kiwi Rupela
Is the following a pure function?
以下是纯函数吗?
function test(min,max) {
return Math.random() * (max - min) + min;
}
My understanding is that a pure function follows these conditions:
我的理解是纯函数遵循以下条件:
- It returns a value computed from the parameters
- It doesn't do any work other than calculating the return value
- 它返回从参数计算的值
- 除了计算返回值,它不做任何工作
If this definition is correct, is my function a pure function? Or is my understanding of what defines a pure function incorrect?
如果这个定义是正确的,我的函数是纯函数吗?或者我对什么定义纯函数的理解不正确?
回答by Christian Benseler
No, it's not. Given the same input, this function will return different values. And then you can't build a 'table' that maps the input and the outputs.
不,这不对。给定相同的输入,此函数将返回不同的值。然后你就不能建立一个映射输入和输出的“表”。
From the Wikipedia article for Pure function:
来自纯函数的维基百科文章:
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices
给定相同的参数值,该函数始终计算相同的结果值。函数结果值不能依赖于在程序执行过程中或程序不同执行之间可能发生变化的任何隐藏信息或状态,也不能依赖于来自 I/O 设备的任何外部输入
Also, another thing is that a pure function can be replaced with a table which represents the mapping from the input and output, as explained in this thread.
此外,另一件事是纯函数可以替换为表示输入和输出映射的表,如本线程中所述。
If you want to rewrite this function and change it to a pure function, you should pass the random value as an argument too
如果要重写此函数并将其更改为纯函数,则也应将随机值作为参数传递
function test(random, min, max) {
return random * (max - min) + min;
}
and then call it this way (example, with 2 and 5 as min and max):
然后以这种方式调用它(例如,以 2 和 5 作为最小值和最大值):
test( Math.random(), 2, 5)
回答by senderle
The simple answer to your question is that Math.random()violates rule #2.
您问题的简单答案是Math.random()违反规则#2。
Many other answers here have pointed out that the presence of Math.random()means that this function is not pure. But I think it's worth saying whyMath.random()taints functions that use it.
这里的许多其他答案都指出,存在Math.random()意味着此功能不纯。但我认为值得一提的是为什么Math.random()使用它的函数会被污染。
Like all pseudorandom number generators, Math.random()starts with a "seed" value. It then uses that value as the starting point for a chain of low-level bit manipulations or other operations that result in an unpredictable (but not really random) output.
像所有伪随机数生成器一样,Math.random()从“种子”值开始。然后它使用该值作为一连串低级位操作或其他导致不可预测(但不是真正随机)输出的操作的起点。
In JavaScript, the process involved is implementation-dependent, and unlike many other languages, JavaScript provides no way to select the seed:
在 JavaScript 中,所涉及的过程依赖于实现,并且与许多其他语言不同,JavaScript没有提供选择种子的方法:
The implementation selects the initial seed to the random number generation algorithm; it cannot be chosen or reset by the user.
实现选择初始种子给随机数生成算法;它不能由用户选择或重置。
That's why this function isn't pure: JavaScript is essentially using an implicit function parameter that you have no control over. It's reading that parameter from data calculated and stored elsewhere, and therefore violates rule #2 in your definition.
这就是这个函数不是纯函数的原因:JavaScript 本质上使用了一个你无法控制的隐式函数参数。它从其他地方计算和存储的数据中读取该参数,因此违反了定义中的规则 #2。
If you wanted to make this a pure function, you could use one of the alternative random number generators described here. Call that generator seedable_random. It takes one parameter (the seed) and returns a "random" number. Of course, this number isn't really random at all; it is uniquely determined by the seed. That's why this is a pure function. The output of seedable_randomis only "random" in the sense that predicting the output based on the input is difficult.
如果你想让它成为一个纯函数,你可以使用这里描述的替代随机数生成器之一。调用该生成器seedable_random。它接受一个参数(种子)并返回一个“随机”数。当然,这个数字根本不是随机的。它由种子唯一确定。这就是为什么这是一个纯函数。的输出seedable_random只是“随机”,因为很难根据输入预测输出。
The pure version of this function would need to take threeparameters:
这个函数的纯版本需要三个参数:
function test(min, max, seed) {
return seedable_random(seed) * (max - min) + min;
}
For any given triple of (min, max, seed)parameters, this will always return the same result.
对于任何给定的三元组(min, max, seed)参数,这将始终返回相同的结果。
Note that if you wanted the output of seedable_randomto be trulyrandom, you'd need to find a way to randomize the seed! And whatever strategy you used would inevitably be non-pure, because it would require you to gather information from a source outside your function. As mtraceurand jpmc26remind me, this includes all physical approaches: hardware random number generators, webcams with lens caps, atmospheric noise collectors-- even lava lamps. All of these involve using data calculated and stored outside the function.
请注意,如果您想要的输出seedable_random是真正随机的,你需要找到一种方法,随机种子!无论您使用什么策略,都不可避免地是不纯的,因为它需要您从职能之外的来源收集信息。正如mtraceur和jpmc26提醒我的那样,这包括所有物理方法:硬件随机数发生器、带镜头盖的网络摄像头、大气噪声收集器——甚至熔岩灯。所有这些都涉及使用在函数外部计算和存储的数据。
回答by TKoL
A pure function is a function where the return value is only determined by its input values, without observable side effects
纯函数是返回值仅由其输入值决定的函数,没有可观察到的副作用
By using Math.random, you are determining its value by something other than input values. It's not a pure function.
通过使用 Math.random,您可以通过输入值以外的其他值来确定其值。它不是一个纯函数。
回答by Shubhnik Singh
No, it isn't a pure function because its output doesn't depend onlyon the input provided (Math.random() can output any value), while pure functions should always output the same value for same inputs.
没有,它不是纯功能,因为它的输出不依赖仅上(的Math.random()能够输出的任何值)提供的输入,而纯函数应该总是输出相同的输入相同的值。
If a function is pure, it's safe to optimize away multiple calls with the same inputs and just reuse the result of an earlier call.
如果函数是纯函数,则可以安全地将具有相同输入的多个调用优化掉,并仅重用先前调用的结果。
P.S for me at least and for many others, redux made the term pure functionpopular. Straight from the redux docs:
PS 至少对我和其他许多人来说,redux 使纯函数这个术语流行起来。直接来自 redux 文档:
Things you should never do inside a reducer:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
在减速器中你永远不应该做的事情:
改变它的论点;
执行 API 调用和路由转换等副作用;
调用非纯函数,例如 Date.now() 或 Math.random()。
回答by Adam Kotwasinski
From mathematical point of view, your signature is not
从数学的角度来看,你的签名不是
test: <number, number> -> <number>
but
但
test: <environment, number, number> -> <environment, number>
where the environmentis capable of providing results of Math.random().
And actually generating the random value mutates the environment as a side effect, so you also return a new environment, which is not equal to the first one!
其中environment能够提供 的结果Math.random()。而实际上生成随机值会变异环境作为副作用,所以你也返回了一个新的环境,它不等于第一个!
In other words, if you need any kind of input that does not come from initial arguments (the <number, number>part), then you need to be provided with execution environment (that in this example provides state for Math). The same applies to other things mentioned by other answers, like I/O or such.
换句话说,如果您需要任何不是来自初始参数(<number, number>部分)的输入,那么您需要提供执行环境(在本例中为 提供状态Math)。这同样适用于其他答案提到的其他事物,例如 I/O 等。
As an analogy, you can also notice this is how object-oriented programming can be represented - if we say, e.g.
作为一个类比,您还可以注意到这就是面向对象编程的表示方式 - 如果我们说,例如
SomeClass something
T result = something.foo(x, y)
then actually we are using
那么实际上我们正在使用
foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>
with the object that has its method invoked being part of the environment. And why the SomeClasspart of result? Because something's state could have changed as well!
调用其方法的对象是环境的一部分。为什么SomeClass是结果的一部分?因为something的状态也可能发生了变化!
回答by Rishabh Mishra
Pure functions always return the same value for same input. Pure functions are predictable and are referential transparent which means that we can replace the function call with the output returned and it will not change the working of the program.
纯函数总是为相同的输入返回相同的值。纯函数是可预测的并且是引用透明的,这意味着我们可以用返回的输出替换函数调用,并且不会改变程序的工作。
https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md
https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md
回答by Davislor
In addition to the other answers that correctly point out how this function is non-deterministic, it also has a side-effect: it will cause future calls to math.random()to return a different answer. And a random-number generator that doesn't have that property will generally perform some kind of I/O, such as to read from a random device provided by the OS. Either is verboten for a pure function.
除了正确指出此函数如何具有不确定性的其他答案之外,它还具有副作用:它会导致未来的调用math.random()返回不同的答案。不具有该属性的随机数生成器通常会执行某种 I/O,例如从操作系统提供的随机设备读取。对于纯函数,两者都是禁止的。
回答by Héctor
No, it isn't. You can't figure out the result at all, so this piece of code can't be tested. To make that code testable, you need to extract the component that generates the random number:
不,不是。你根本想不通结果,所以这段代码无法测试。为了使该代码可测试,您需要提取生成随机数的组件:
function test(min, max, generator) {
return generator() * (max - min) + min;
}
Now, you can mock the generator and test your code properly:
现在,您可以模拟生成器并正确测试您的代码:
const result = test(1, 2, () => 3);
result == 4 //always true
And in your "production" code:
在您的“生产”代码中:
const result = test(1, 2, Math.random);
回答by Joshua
Would you be fine with the following:
你会不会有以下情况:
return ("" + test(0,1)) + test(0,1);
be equivalent to
相当于
var temp = test(0, 1);
return ("" + temp) + temp;
?
?
You see, the definition of pure is a function whose output does not change with anything other than its inputs. If we say that JavaScript had a way to tag a function pure and take advantage of this, the optimizer would be allowed to rewrite the first expression as the second.
你看,pure 的定义是一个函数,它的输出不会随输入以外的任何东西改变。如果我们说 JavaScript 有一种方法可以标记一个纯函数并利用它,优化器将被允许将第一个表达式重写为第二个。
I have practical experience with this. SQL server allowed getdate()and newid()in "pure" functions and the optimizer would dedupe calls at will. Sometimes this would do something dumb.
我有这方面的实践经验。SQL 服务器允许getdate()并newid()在“纯”函数中,优化器会随意删除重复调用。有时这会做一些愚蠢的事情。

