Скажем, у нас есть нормальная чистая функция, такая как
function add(a, b) {
return a + b
}
И тогда мы изменим его так, что он имеет побочный эффект
function add(a, b) {
writeToDatabase(Math.random())
return a + b;
}
Насколько я знаю, это не считается чистой функцией, потому что я часто слышу, как люди называют чистые функции «функциями без побочных эффектов». Однако он ведет себя как чистая функция, поскольку он возвращает тот же вывод для тех же входов.
Есть ли другое название для этого типа функции, оно безымянное или все еще на самом деле чистое, и я ошибаюсь в определении чистоты?
writeToDatabase
сбой, это может вызвать исключение, в результате чего ваша втораяadd
функция иногда создает исключение, даже если она вызывается с теми же аргументами, что раньше не имели проблем ... в большинстве случаев наличие побочных эффектов приводит к возникновению такого рода связанных с ошибкой условий, «чистота ввода-вывода».F(x)
определяется для возврата,true
если он вызывается с тем же аргументом, что и предыдущий вызов. Очевидно, что с последовательностью{1,2,2} => {undefined, false, true}
это является детерминированным, но это дает разные результаты дляF(2)
.Ответы:
Я не уверен в универсальных определениях чистоты, но с точки зрения Haskell (языка, где программисты, как правило, заботятся о таких вещах, как чистота и ссылочная прозрачность), только первая из ваших функций является «чистой». Вторая версия
add
не чиста . Так что в ответ на ваш вопрос я бы назвал это "нечистым";)Согласно этому определению, чистая функция - это функция, которая:
С этим определением ясно, что ваша вторая функция не может считаться чистой, поскольку она нарушает правило 2. То есть следующие две программы НЕ эквивалентны:
а также
Это потому, что, хотя обе функции будут возвращать одно и то же значение, функция
f
будет писать в базу данных дважды, ноg
будет писать один раз! Весьма вероятно, что записи в базу данных являются частью наблюдаемого поведения вашей программы, и в этом случае я показал, что ваша вторая версияadd
не "чистая".Если записи в базу данных не являются наблюдаемой частью поведения вашей программы, то обе версии
add
можно считать эквивалентными и чистыми. Но я не могу придумать сценарий, когда запись в базу данных не имеет значения. Даже ведение журнала имеет значение!источник
f(x)
зависит не только отx
, но и от некоторой внешней глобальной переменнойy
. Затем, еслиf
имеет свойство RT, вы можете свободно поменять местами все его вхождения с возвращаемым значением, пока вы не коснетесьy
. Да, мой пример сомнителен. Но важная вещь: еслиf
запись в базу данных (или запись в журнал) теряет свойство RT: теперь не имеет значения, оставляете ли вы глобальный без измененийy
, вы знаете, что значение вашей программы меняется в зависимости от того, действительно ли вы позвонитеf
или просто используйте его возвращаемое значение.Такая функция называется
По поводу состояния:
В зависимости от того, чье определение функции вы используете, функция не имеет состояния. Если вы пришли из объектно-ориентированного мира, помните, что
x.f(y)
это метод. Как функция это будет выглядеть такf(x,y)
. И если вы находитесь в замыканиях с закрытой лексической областью, помните, что неизменное состояние может также быть частью выражения функций. Это только изменчивое состояние, которое будет влиять на функции детерминированного характера. Таким образом, f (x) = x + 1 является детерминированным, пока 1 не изменяется. Не имеет значения, где хранится 1.Ваши функции оба детерминированы. Ваша первая тоже чистая функция. Ваш второй не чист.
Точка 1 означает детерминированность . Пункт 2 означает ссылочную прозрачность . Вместе они означают, что чистая функция позволяет изменять только свои аргументы и возвращаемое значение. Ничто другое не вызывает изменений. Больше ничего не изменилось.
источник
Math.random()
. Так что нет, если только мы не примем PRNG (вместо физического RNG) И не посчитаем, что PRNG указывают часть ввода (а это не так, ссылка жестко закодирована), это не детерминистично.Если вы не заботитесь о побочном эффекте, то он прозрачен. Конечно, возможно, что вам все равно, но кто-то другой заботится, поэтому применимость этого термина зависит от контекста.
Я не знаю общего термина для точно описываемых вами свойств, но важным подмножеством являются те, которые являются идемпотентными . В информатике, немного отличающейся от математики *, идемпотентная функция - это функция, которая может повторяться с тем же эффектом; то есть чистый побочный эффект от многократного выполнения такой же, как и один раз.
Таким образом, если ваш побочный эффект заключается в обновлении базы данных с определенным значением в определенной строке или в создании файла с точно согласованным содержимым, то он будет идемпотентным , но если он будет добавлен в базу данных или добавлен в файл тогда бы этого не было.
Комбинации идемпотентных функций могут быть или не быть идемпотентными в целом.
* Использование идемпотента в информатике иначе, чем в математике, по-видимому, произошло из-за неправильного использования математического термина, который затем был принят, потому что концепция полезна.
источник
(f x, f x)
сlet y = f x in (y, y)
будет работать в свободное дисковое пространство-исключений в два раза быстрее , можно утверждать , что эти крайние случаи вас не волнуют, но с таким нечетким определением мы могли бы также назватьnew Random().Next()
референциально прозрачным, потому что, черт возьми, мне все равно, какое число я получу в любом случае.Random.Next
в .NET действительно имеет побочные эффекты. Даже очень. Если вы можетеNext
назначить ее переменной, а затемNext
снова вызвать и назначить другую переменную, скорее всего, они не будут одинаковыми. Зачем? Потому что вызовNext
изменяет скрытое внутреннее состояниеRandom
объекта. Это полярная противоположность ссылочной прозрачности. Я не понимаю вашего заявления о том, что «основные эффекты» не могут быть побочными эффектами. В императивном коде чаще всего встречается побочный эффект, потому что императивные программы имеют состояние с учетом состояния.Я не знаю, как называются такие функции (или есть ли даже какое-то систематическое имя), но я бы назвал функцию, которая не является чистой (как и другие ответы, сжатые), но всегда возвращает один и тот же результат, если снабжена теми же параметрами, параметры »(по сравнению с функцией его параметров и некоторым другим состоянием). Я бы назвал это просто функцией, но, к сожалению, когда мы говорим «функция» в контексте программирования, мы имеем в виду что-то, что вообще не должно быть действительной функцией.
источник
Это в основном зависит от того, заботишься ты о нечистоте или нет. Если семантика этой таблицы такова, что вам все равно, сколько записей, то она чистая. Иначе, это не чисто.
Или, другими словами, это нормально, если оптимизация, основанная на чистоте, не нарушает семантику программы.
Более реалистичный пример был бы, если вы пытались отладить эту функцию и добавили операторы регистрации. Технически, регистрация - побочный эффект. Логи делают это нечистым? Нет.
источник
Я бы сказал, что лучше всего спросить не о том, как мы это называем, а о том, как мы будем анализировать такой кусок кода. И мой первый ключевой вопрос в таком анализе:
Это легко проиллюстрировать в Haskell (и это предложение - только половина шутки). Пример случая «нет» будет примерно таким:
В этом примере действие, которое мы предпринимаем (выводим строку
"I'm doubling some number"
), не влияет на отношенияx
и результат. Это означает, что мы можем реорганизовать его таким образом (используяApplicative
класс и его*>
оператор), что показывает, что функция и эффект фактически ортогональны:Так что в этом случае я бы лично сказал, что это тот случай, когда вы можете выделить чистую функцию. Об этом много говорят на Haskell - учатся выделять чистые части из эффективного кода.
Пример типа «да», где чистая и эффективная части не ортогональны:
Теперь строка, которую вы печатаете, зависит от значения
x
. Функция часть (умножитьx
на два), однако, не зависит от влияния на всех, так что мы можем по- прежнему учитывать это:Я мог бы продолжить приводить другие примеры, но я надеюсь, что этого достаточно, чтобы проиллюстрировать точку, с которой я начал: вы не «называете» это чем-то, вы анализируете, как чистая и эффективная части соотносятся, и выделяете их, когда это так. в ваших интересах.
Это одна из причин, по которой Haskell
Monad
так широко использует свой класс. Монады являются (помимо прочего) инструментом для проведения такого анализа и рефакторинга.источник
Функции, которые предназначены для побочных эффектов, часто называют эффективными . Пример https://slpopejoy.github.io/posts/Effectful01.html
источник