В чем разница между Идемпотентной и детерминированной функциями?
являются ли они оба (идемпотентные функции и детерминированные функции) просто функциями, которые возвращают один и тот же результат при одинаковых входных данных?
или есть различие, которого мне не хватает? (И если есть различие, не могли бы вы помочь мне понять, что это такое)
2 ответов
проще говоря:
- детерминированная функция: выход основан полностью и только на входных значениях и ничего больше: нет другого (скрытого) входа или состояния, на которое он полагается для генерации своего выхода.
- идемпотентности: практически определение что вы можете безопасно вызвать такую же функцию множественные времена без страха отрицательных побочных эффектов. Более формально: нет изменения государство между последующими идентичными вызовами.
идемпотентность не подразумевает определенности (поскольку функция может изменять состояние при первом вызове, будучи идемпотентной при последующих вызовах), но все детерминированные функции по своей сути являются идемпотентными (поскольку нет внутреннего состояния для сохранения между вызовами).
детерминированности
например, в SQL UCASE(val)
, или в C#/.NET String.IndexOf
оба детерминированы, потому что выход зависит только от вход. Обратите внимание, что в экземпляре методы (например,IndexOf
) объект экземпляра (т. е. скрытый this
параметр) считается входным, даже если он "скрыт":
"foo".IndexOf("o") == 1 // first cal
"foo".IndexOf("o") == 1 // second call
// the third call will also be == 1
тогда как в SQL NOW()
или в C# / .NET DateTime.UtcNow
не является детерминированным, потому что выходные данные изменяются, даже если входные данные остаются неизменными (обратите внимание, что геттеры свойств в .NET эквивалентны методу, который не принимает никаких параметров, кроме неявного this
параметр):
DateTime.UtcNow == 2016-10-27 18:10:01 // first call
DateTime.UtcNow == 2016-10-27 18:10:02 // second call
идемпотентности
хорошим примером в .NET является Dispose()
способ: см.Должен IDisposable.Реализации Dispose () являются идемпотентными?
метод Dispose должен вызываться несколько раз, без исключения.
Итак, если родительский компонент X
делает первоначальный вызов foo.Dispose()
затем он вызовет операцию удаления и X
теперь можно рассмотреть foo
быть утилизированным. Затем выполнение / управление переходит к другому компоненту Y
который также пытается избавиться от foo
, после Y
звонки foo.Dispose()
это тоже может ожидать foo
быть утилизированным (что и есть), хотя X
уже распорядилась. Это значит Y
не нужно проверять, чтобы увидеть, если foo
уже утилизирован, экономя время разработчика - а также устраняя ошибки при вызове Dispose
второй раз может вызвать исключение, для образец.
другой (общий) пример находится в REST: RFC для HTTP1.1 заявляет, что GET
, HEAD
, PUT
и DELETE
идемпотентны, но POST
нет (https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)
методы также могут иметь свойство "идемпотентности" в том, что (помимо ошибок или проблем с истечением срока действия) Побочные эффекты n > 0 идентичных запросов такие же, как и для одного запроса. Методы GET, HEAD, PUT и удалить поделиться этим свойством. Кроме того, методы OPTIONS и TRACE не должны иметь побочных эффектов и поэтому по своей сути являются идемпотентными.
если вы используете DELETE
затем:
Client->Server: DELETE /foo/bar
// `foo/bar` is now deleted
Server->Client: 200 OK
Client->Server DELETE /foo/bar
// foo/bar` is already deleted, so there's nothing to do, but inform the client that foo/bar doesn't exist
Server->Client: 404 Not Found
// the client asks again:
Client->Server: DELETE /foo/bar
// foo/bar` is already deleted, so there's nothing to do, but inform the client that foo/bar doesn't exist
Server->Client: 404 Not Found
Итак, вы видите в приведенном выше примере, что DELETE
является идемпотентным в том, что состояние сервера не изменилось между последними двумя DELETE
запросы, но это не детерминировано, потому что сервер вернул 200
для первого запроса, но 404
для второго запрос.
детерминированная функция-это просто функция в математическом смысле. Учитывая один и тот же вход, вы всегда получаете один и тот же выход. С другой стороны, идемпотентная функция-это функция, удовлетворяющая тождеству
f(f(x)) = f(x)
в качестве простого примера. Если UCase()
- это функция, которая преобразует строку в строку верхнего регистра, а затем явно UCase(Ucase(s)) = UCase(s)
.
идемпотентные функции являются подмножеством всех функций.