Является ли функция, которая называет Math.random() чистой?
Является ли следующая чистая функция?
function test(min,max) {
return Math.random() * (max - min) + min;
}
Я понимаю, что чистая функция следует этим условиям:
- Он возвращает значение, вычисленное по параметрам
- Он не выполняет никакой другой работы, кроме вычисления возвращаемого значения
Если это определение верное, является ли моя функция чистой? Или мое понимание того, что определяет чистую функцию неправильно?
Ответы
Ответ 1
Нет, нет. Учитывая тот же ввод, эта функция возвращает разные значения. И тогда вы не можете построить "таблицу", которая отображает входные данные и выходы.
Из статьи в Википедии для Чистая функция:
Функция всегда оценивает одно и то же значение результата, учитывая тот же значение аргумента. Значение результата функции не может зависеть от скрытая информация или состояние, которое может меняться при выполнении программы продолжается или между различными исполнениями программы, и не может зависят от любого внешнего входа от устройств ввода/вывода
Кроме того, еще одна вещь заключается в том, что чистую функцию можно заменить таблицей, которая представляет собой отображение из ввода и вывода, как описано в этой теме.
Если вы хотите переписать эту функцию и изменить ее на чистую функцию, вы также должны передать случайное значение в качестве аргумента
function test(random, min, max) {
return random * (max - min) + min;
}
а затем вызовите его таким образом (например, с 2 и 5 как мин и макс):
test( Math.random(), 2, 5)
Ответ 2
Простой ответ на ваш вопрос: Math.random()
нарушает правило № 2.
Многие другие ответы здесь указывают на то, что наличие Math.random()
означает, что эта функция не является чистой. Но я думаю, что стоит сказать, почему Math.random()
использует функции taints, которые его используют.
Как и все генераторы псевдослучайных чисел, Math.random()
начинается с значения "семя". Затем он использует это значение в качестве отправной точки для цепи низкоуровневых манипуляций с битами или других операций, которые приводят к непредсказуемому (но не очень случайному) выводу.
В JavaScript этот процесс зависит от реализации, и в отличие от многих других языков, JavaScript предоставляет способ выбора семени:
Реализация выбирает начальное семя для алгоритма генерации случайных чисел; он не может быть выбран или reset пользователем.
Вот почему эта функция не чиста: JavaScript по сути использует неявный функциональный параметр, который вы не контролируете. Он считывает этот параметр из данных, вычисленных и сохраненных в другом месте, и поэтому нарушает правило №2 в вашем определении.
Если вы хотите сделать это чистой функцией, вы можете использовать один из альтернативных генераторов случайных чисел, описанный здесь здесь. Вызовите этот генератор seedable_random
. Он принимает один параметр (семя) и возвращает "случайное" число. Конечно, это число действительно не случайное; он однозначно определяется семенем. Вот почему это чистая функция. Выходной сигнал seedable_random
является только "случайным" в том смысле, что прогнозирование выхода на основе ввода затруднено.
Чистая версия этой функции должна принимать три параметра:
function test(min, max, seed) {
return seedable_random(seed) * (max - min) + min;
}
Для любой заданной тройки параметров (min, max, seed)
это всегда возвращает тот же результат.
Обратите внимание, что если вы хотите, чтобы вывод seedable_random
был действительно случайным, вам нужно найти способ рандомизировать семя! И любая стратегия, которую вы использовали, неизбежно будет нечистой, потому что это потребует от вас сбора информации из источника вне вашей функции. Поскольку mtraceur и jpmc26 напоминают мне, это включает в себя все физические подходы: аппаратные генераторы случайных чисел, веб-камеры с крышками объективов, атмосферные шумоглушители - даже лавовые лампы. Все это связано с использованием данных, вычисленных и сохраненных вне функции.
Ответ 3
Чистая функция - это функция, в которой возвращаемое значение определяется только его входными значениями без наблюдаемых побочных эффектов
Используя Math.random, вы определяете его значение чем-то другим, кроме входных значений. Это не чистая функция.
источник
Ответ 4
Нет, это не чистая функция, потому что ее вывод не зависит только от введенного ввода (Math.random() может выводить любое значение), тогда как чистые функции всегда должны выводить одно и то же значение для тех же самых входов.
Если функция чиста, она безопасна для оптимизации нескольких вызовов с одними и теми же входами и просто повторного использования результата более раннего вызова.
P.S для меня, по крайней мере, и для многих других, redux сделал термин чистой функции популярным. Прямо из документов redux:
Вещи, которые вы никогда не должны делать внутри редуктора:
-
Мутировать свои аргументы,
-
Выполнять побочные эффекты, такие как вызовы API и переходы маршрутизации;
-
Вызов нечистых функций, например. Date.now() или Math.random().
Ответ 5
С математической точки зрения ваша подпись не
test: <number, number> -> <number>
но
test: <environment, number, number> -> <environment, number>
где environment
способен предоставлять результаты Math.random()
.
И фактически генерация случайного значения мутирует среду как побочный эффект, поэтому вы также возвращаете новую среду, которая не равна первой!
Другими словами, если вам нужен какой-либо вход, который не исходит из начальных аргументов (часть <number, number>
), вам необходимо предоставить среду исполнения (которая в этом примере предоставляет состояние для Math
), То же самое относится к другим вещам, упомянутым в других ответах, таких как I/O или тому подобное.
Как аналогия, вы также можете заметить, что объектно-ориентированное программирование может быть представлено - если мы скажем, например,
SomeClass something
T result = something.foo(x, y)
то на самом деле мы используем
foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>
с объектом, для которого его метод вызван как часть среды. И почему результат SomeClass
результата? Потому что состояние something
также может быть изменено!
Ответ 6
Чистые функции всегда возвращают одно и то же значение для одного входа.
Чистая функция предсказуема и является ссылочной прозрачной, что означает, что мы можем заменить вызов функции возвращенным результатом и не изменим работу программы.
https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md
Ответ 7
В дополнение к другим ответам, в которых правильно указывается, как эта функция не является детерминированной, она также имеет побочный эффект: она вызовет будущие вызовы math.random()
, чтобы вернуть другой ответ. Генератор случайных чисел, который не имеет этого свойства, обычно выполняет какой-то ввод-вывод, например, для чтения с произвольного устройства, предоставляемого ОС. Либо это verboten для чистой функции.
Ответ 8
Нет, это не так. Вы не можете понять результат вообще, поэтому этот фрагмент кода не может быть протестирован. Чтобы проверить этот код, вам нужно извлечь компонент, который генерирует случайное число:
function test(min, max, generator) {
return generator() * (max - min) + min;
}
Теперь вы можете издеваться над генератором и правильно проверить свой код:
const result = test(1, 2, () => 3);
result == 4 //always true
И в вашем "производственном" коде:
const result = test(1, 2, Math.random);
Ответ 9
Вы будете в порядке со следующим:
return ("" + test(0,1)) + test(0,1);
эквивалентно
var temp = test(0, 1);
return ("" + temp) + temp;
?
Вы видите, определение pure - это функция, выход которой не изменяется ни с чем другим, кроме ее входов. Если мы скажем, что JavaScript имел способ пометить функцию pure и воспользоваться ею, оптимизатору будет разрешено переписать первое выражение как второе.
У меня есть практический опыт в этом. SQL-сервер разрешил getdate()
и newid()
в "чистых" функциях, и оптимизатор по умолчанию будет дедуксировать. Иногда это делало бы что-то немым.