в «чистых» функциях и оптимизатор будет дедуплировать вызовы по желанию. Иногда это делает что-то глупое.

тся ли следующее чистой функцией?

function test(min,max) {
   return  Math.random() * (max - min) + min;
}

Насколько я понимаю, чистая функция соответствует следующим условиям:

Возвращает значение, вычисленное по параметрамОн не выполняет никакой работы, кроме вычисления возвращаемого значения.

Если это определение верно, моя функция - чистая функция? Или мое понимание того, что определяет чистую функцию, неверно?

 jdm01 нояб. 2017 г., 09:29
Есть ли понятие полупюрной функции, учитывающее случайность? Например.test(a,b) всегда возвращает один и тот же объектRandom(a,b) (которые могут представлять разные конкретные числа)? Если вы продолжаетеRandom Символично, что это чисто в классическом смысле, если вы оцениваете это рано и вводите числа, возможно, как своего рода оптимизацию, функция все еще сохраняет некоторую «чистоту».
 Paul Draper31 окт. 2017 г., 17:02
«Это не делает никакой работы, кроме вычисления возвращаемого значения», но это вызываетMath.random() который меняет состояние ГСЧ.
 Steve Kuo02 нояб. 2017 г., 21:51
«Любой, кто рассматривает арифметические методы получения случайных цифр, конечно, находится в состоянии греха». - Джон фон Нейман
 luqui03 нояб. 2017 г., 03:15
@jdm, если вы следите за потоком "полупрозрачный", где вы рассматриваете функции как чистые по модулювполне определенный побочные эффекты, вы можете в конечном итоге изобрести монады. Добро пожаловать на темную сторону. > :)
 MVCDS31 окт. 2017 г., 21:54
Второй пункт больше похож на «он не меняет внешнего (для функции) состояния»; и первый должен быть дополнен чем-то вроде «он возвращает то же значение, вычисленное из тех же параметров», как написано ниже

Ответы на вопрос(9)

Решение Вопроса

это не так. При одинаковом входе эта функция будет возвращать разные значения. И тогда вы не можете построить «таблицу», которая отображает вход и выход.

Из статьи Википедии дляЧистая функция:

Функция всегда оценивает одно и то же значение результата, учитывая одно и то же значение аргумента. Значение результата функции не может зависеть от какой-либо скрытой информации или состояния, которое может измениться во время выполнения программы или между различными выполнениями программы, а также не может зависеть от какого-либо внешнего ввода с устройств ввода-вывода

Кроме того, другая вещь состоит в том, что чистая функция может быть заменена таблицей, которая представляет отображение из входных и выходных данных, как объясняется вэта тема.

Если вы хотите переписать эту функцию и заменить ее на чистую функцию, вы должны передать случайное значение в качестве аргумента

function test(random, min, max) {
   return random * (max - min) + min;
}

и затем назовите это так (например, с 2 и 5 как min и max):

test( Math.random(), 2, 5)
 Pharap02 нояб. 2017 г., 12:39
@ cᴏʟᴅsᴘᴇᴇᴅ Существуют способы иметь RNG, которые работают с чистыми функциями, но это включает передачу состояния RNG в функцию и возвращение функции замещающего состояния RNG, как это достигается на Haskell (функциональном языке программирования, обеспечивающем функциональную чистоту). Это.
 wchargin31 окт. 2017 г., 21:25
@ LegionMammal978… и делай это атомарно.
 LegionMammal97831 окт. 2017 г., 21:09
@ cᴏʟᴅsᴘᴇᴇᴅ Даже тогда, это все еще будет иметь побочные эффекты (изменение будущегоMath.random выход); чтобы он был чистым, вам нужно каким-то образом сохранить текущее состояние ГСЧ, повторно заполнить его, вызватьMath.randomи восстановить его в прежнее состояние.
 coldspeed31 окт. 2017 г., 21:05
Что делать, если вы должны заново генерировать генератор случайных чисел внутри функции перед вызовомMath.random?
 zfrisch31 окт. 2017 г., 21:12
@ cᴏʟᴅsᴘᴇᴇᴅ Все вычисленные значения ГСЧ основаны на случайной случайности. Что-то должно быть запущено внизу, что заставляет его казаться случайным, и вы не можете объяснить это, делая это нечистым. Кроме того, и, возможно, что более важно для вашего вопроса, вы не можете посеять Math.random

только на предоставленном входе (Math.random () может вывести любое значение), в то время как чистые функции должны всегда выводить одно и то же значение для одних и тех же входов.

Если функция чистая, безопасно оптимизировать несколько вызовов с одинаковыми входами и просто повторно использовать результат более раннего вызова.

P.S для меня, по крайней мере, и для многих других, редукс сделал терминчистая функция популярный.Прямо из редукса документов:

То, что вы никогда не должны делать внутри редуктора:

Мутировать его аргументы;

Выполнять побочные эффекты, такие как вызовы API и переходы маршрутизации;

Вызовите не чистые функции, например Date.now () или Math.random ().

 Shubhnik Singh31 окт. 2017 г., 13:36
Хотя другие предоставили отличные ответы, но я не смог устоять перед собой, когда мне пришло в голову избыточное документирование, и Math.random () специально упомянул в них :)

которые правильно указывают, как эта функция недетерминирована, она также имеет побочный эффект: она вызовет будущие вызовыmath.random() вернуть другой ответ. А генератор случайных чисел, у которого нет этого свойства, обычно выполняет какой-либо ввод-вывод, например, для чтения со случайного устройства, предоставляемого ОС. Либо является верботеном для чистой функции.

в которой возвращаемое значение определяется только его входными значениями без видимых побочных эффектов.

Используя Math.random, вы определяете его значение чем-то, кроме входных значений. Это не чистая функция.

источник

это не так. Вы не можете выяснить результат вообще, поэтому этот кусок кода не может быть протестирован. Чтобы сделать этот код тестируемым, вам нужно извлечь компонент, который генерирует случайное число:

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);
 PJTraill01 нояб. 2017 г., 22:10
▲ для вашей мысли о проверяемости. С небольшой осторожностью вы можете также производить повторяющиеся тесты, принимаяutil.Random, который можно запустить в начале тестового прогона, чтобы повторить старое поведение или для нового (но повторяемого) прогона. Если многопоточность, вы можете сделать это в основном потоке и использовать этоRandom сеять повторяемую локальную нитьRandoms. Однако, насколько я понимаю,test(int,int,Random) не считается чистым, так как он изменяет состояниеRandom.

Будете ли вы в порядке со следующим:

return ("" + test(0,1)) + test(0,1);

быть эквивалентным

var temp = test(0, 1);
return ("" + temp) + temp;

?

Видите ли, определение pure - это функция, чей вывод не изменяется ни с чем, кроме его входных данных. Если мы скажем, что в JavaScript есть способ пометить чистую функцию и воспользоваться этим, оптимизатору будет разрешено переписать первое выражение как второе.

У меня есть практический опыт с этим. SQL-сервер разрешенgetdate() а такжеnewid() в «чистых» функциях и оптимизатор будет дедуплировать вызовы по желанию. Иногда это делает что-то глупое.

Math.random() нарушает правило № 2.

Многие другие ответы здесь указывают на то, что присутствиеMath.random() означает, что эта функция не является чистой. Но я думаю, что стоит сказатьПочему Math.random() портит функции, которые его используют.

Как и все генераторы псевдослучайных чисел,Math.random() начинается со значения "семя". Затем он использует это значение в качестве отправной точки для цепочки низкоуровневых битовых манипуляций или других операций, которые приводят к непредсказуемым (но не совсемслучайный) выход.

В JavaScript этот процесс зависит от реализации, и, в отличие от многих других языков, JavaScript обеспечиваетнет возможности выбрать семя:

Реализация выбирает начальное начальное число для алгоритма генерации случайных чисел; он не может быть выбран или сброшен пользователем.

Вот почему эта функция не является чистой: 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 напомните мне, это включает в себя все физические подходы:аппаратные генераторы случайных чисел, веб-камеры с крышками объектива, коллекторы атмосферного шума -- четныйлавовые лампы, Все это включает использование данных, рассчитанных и сохраненных вне функции.

 senderle01 нояб. 2017 г., 19:28
@mtraceur, это правильно. Но я не думаю, что ответ сильно изменится. Фактически, именно поэтому я не трачу время на разговоры о «состоянии» в своем ответе. Чтение с аппаратного RNG также означает чтение «данных, рассчитанных и сохраненных в другом месте». Просто данные рассчитываются и хранятся на физическом носителе самого компьютера, когда он взаимодействует с окружающей средой.
 mtraceur01 нояб. 2017 г., 19:17
Как изменится этот ответ, еслиMath.random не использовал PRNG, но вместо этого был реализован с использованием аппаратного RNG? Аппаратный ГСЧ в действительности не имеет состояния в обычном смысле, но он выдает случайные значения (и, следовательно, выходные данные функций все равно различаются независимо от входных данных), верно?
 Nate Eldredge31 окт. 2017 г., 15:45
Math.random () не только читает его «семя», но и модифицирует его, так что следующий вызов вернет что-то другое. В зависимости от статического состояния и его модификации определенно плохо для чистой функции.
 jpmc2601 нояб. 2017 г., 22:15
Эта та же логика применима даже к более сложным схемам рандомизации, даже таким, какАтмосферный шум Random.org, +1
 senderle31 окт. 2017 г., 16:12
@NateEldredge, именно так! Хотя простого чтения значения, зависящего от реализации, достаточно, чтобы нарушить чистоту. Например, когда-нибудь замечали, что хэши Python 3 не стабильны между процессами?

С математической точки зрения ваша подпись не

test: <number, number> -> <number>

но

test: <environment, number, number> -> <environment, number>

гдеenvironment способен обеспечить результатыMath.random(), А на самом деле генерация случайного значения изменяет среду как побочный эффект, поэтому вы также возвращаете новую среду, которая не равна первой!

Другими словами, если вам нужен какой-либо вид ввода, который не исходит из начальных аргументов (<number, number> часть), то вам нужно предоставить среду выполнения (которая в этом примере обеспечивает состояние дляMath). То же самое относится и к другим вещам, упомянутым в других ответах, таких как ввод-вывод или тому подобное.

В качестве аналогии вы также можете заметить, что именно так можно представить объектно-ориентированное программирование, например, например.

SomeClass something
T result = something.foo(x, y)

тогда на самом деле мы используем

foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>

с объектом, у которого вызывается его метод, являющимся частью среды. И почемуSomeClass часть результата? Потому чтоsomethingсостояние могло измениться!

 Bergi31 окт. 2017 г., 19:00
Хуже того, среда также мутировала, поэтомуtest: <environment, number, number> -> <environment, number> так должно быть
 IMSoP02 нояб. 2017 г., 17:05
Я не уверен, что пример ОО очень похож.a.F(b, c) можно рассматривать как синтаксический сахар дляF(a, b, c) со специальным правилом для отправки в перегруженные определенияF в зависимости от типаa (это на самом деле, как это представляет Python). Ноa все еще явно в обоих обозначениях, в то время как окружение в не чистой функции никогда не упоминается в исходном коде.
 Adam Kotwasinski02 нояб. 2017 г., 14:45
@ Bergi Да, вы абсолютно правы! Измененный.

го же входа. Чистые функции предсказуемы и прозрачны по ссылкам, что означает, что мы можем заменить вызов функции возвращаемым выводом, и это не изменит работу программы.

https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md

Ваш ответ на вопрос