В чем разница между Идемпотентной и детерминированной функциями?

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

или есть различие, которого мне не хватает? (И если есть различие, не могли бы вы помочь мне понять, что это такое)

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).

идемпотентные функции являются подмножеством всех функций.