Какие именно правила должна соблюдать функция, прежде чем мы сможем назвать ее «идемпотентной»? - PullRequest
9 голосов
/ 02 февраля 2012

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

Однако используемые термины (такие как «отсутствие побочных эффектов» и «возвращение-тот же результат») относительно неоднозначны. Рассмотрим этот кусок кода:

public class test {

    int x = 0;
    java.util.Random r = new java.util.Random();

    public int F() {
        return x + 1;
    }

    public void F2() {
        x = r.nextInt();
    }
}

Можно ли сказать, что F() является идемпотентом, потому что последовательные вызовы F() возвращают одно и то же значение?

Или не идемпотент, поскольку последовательные вызовы F() не возвращают одно и то же значение, если между ними вызывается F2()? 1018 *

PS: " идемпотент ", как определено в информатике, а не по математике.

Ответы [ 4 ]

10 голосов
/ 02 февраля 2012

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

Например, рассмотрим две функции для удаления файла по имени:

1) Функция, которая возвращает успех, если файл не существует.(Поскольку цель операции удаления - сделать файл не существующим.)

2) Функция, которая возвращает ошибку «файл не существует», если файл не существует.(Поскольку файл не может быть удален.)

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

Второй не идемпотентен.Если вы вызовете его один раз и проигнорируете результат, ваш второй вызов потерпит неудачу, и вы подумаете, что не удалили файл.

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

Эта концепция важна в клиент-серверных протоколах.Допустим, вы отправили команду и не получили ответа, возможно, разрывается соединение, возможно, произошел сбой сервера.Итак, вы отправляете команду снова и получаете ответ.Но по первой команде была потеряна команда или ответ?Если команда идемпотентна, это не имеет значения.Вы можете просто использовать результат.

Если протокол гарантирует, что все операции являются идемпотентными, код более низкого уровня может повторить неудачные операции, переключить серверы и в противном случае попытаться «заставить вещи работать», не нарушая семантикуоперации.

Требуется некоторое усилие, чтобы создать идемпотентный протокол.Например, вы можете задаться вопросом, как сделать разумную операцию «удалить файл».Одним из способов является присвоение каждому файлу уникального идентификатора, который изменяется при удалении и повторном создании файла.Затем вы разделяете удаление на две половины.Во-первых, «получить идентификатор из имени» идемпотентно и не работает, если файл не существует.Второе, «удалить идентификатор, если он существует», идемпотентно и успешно, если вы или кто-либо другой удалили файл.(Единственная странность в том, что это не говорит вам наверняка, что вы были тем, кто удалил файл.) Сочетание двух идемпотентных операций обеспечивает желаемую неидемпотентную операцию удаления.

5 голосов
/ 02 февраля 2012

Ваша функция не идемпотентна.Может возвращать разные результаты.При одном и том же входе идемпотентная функция всегда возвращает один и тот же вывод.

Более конкретно, если f () идемпотентен (согласно определению информатики), то:

int result1 = f(x);
// ... some arbitrary code
int result2 = f(x);
assert(result1 == result2);
3 голосов
/ 02 февраля 2012

Попытка суммировать вещи, которые возникли в других ответах и ​​в комментариях:

Существует только одно определение "идемпотента".Функция f является идемпотентной тогда и только тогда, когда f(f(x)) равно f(x) для всех x в области f.

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

Существует более одного определения «функции»,В математике (с традиционной теоретико-множественной конструкцией) функция - это набор пар.«Домен» функции - это набор всех элементов, которые появляются в первой позиции пары.Ни один элемент домена не появляется в первой позиции более чем одной пары в функции.«Диапазон» функции - это набор всех элементов, которые появляются во второй позиции пары.Элементы ассортимента могут появляться более одного раза.Мы говорим, что функция «отображает» каждый элемент своей области на определенный элемент своего диапазона, и мы пишем f(x), чтобы обозначить «второй элемент пары в f, который имеет x в качестве первого элемента».

Итак, ясно, что для функции, которая должна быть идемпотентной, ее диапазон должен быть подмножеством ее области.В противном случае f(f(x)) не имеет смысла.

В вычислениях, и особенно в императивных языках, функция часто определяется как последовательность операторов / инструкций вместе с некоторыми именованными входами и выходами (в большинстве языков)только один выход).«Вызов» функции является обязательной операцией, которая означает выполнение инструкций.Но инструкции на императивном языке могут иметь побочные эффекты: они могут изменить что-то, кроме их результатов.Эта концепция отсутствует в математике, а также в чисто функциональном программировании.

Эти императивные «функции», которые я теперь буду называть «подпрограммами», могут быть согласованы с математическим определением функциидвумя способами:

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

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

Теперь, если мы применим определение «идемпотент» в случае 1, мы оцениваем, является ли математическая функция, для которой определенная подпрограмма предназначена для реализации , идемпотентной.Если подпрограмма делает что-то кроме реализации математической функции, например, если у нее есть какие-либо побочные эффекты, тогда мы находимся на очень шатком основании и получим вводящие в заблуждение результаты.Например, функцию int f(int i) { puts("hello!"); return i; } можно рассматривать как идемпотентную на том основании, что «это реализация функции идентичности!».И это правда, если вы игнорируете побочные эффекты, но это означает, что определение бесполезно для каких-либо практических целей, потому что после учета побочных эффектов выполнение выражения f(f(0)) отличается от выполнения выражения f(0).f(f(0)) не эквивалентно f(0), даже если их возвращаемые значения равны, и мы можем заменить одно только другим, если не заботимся о (той части) выходных данных программы.

Если мы применим определение «идемпотента» к функциям состояний машины в случае 2, мы оцениваем , является ли вызов функции (с конкретными аргументами) идемпотентной операцией над состоянием машины .Тогда моя функция f выше, очевидно, равна , а не идемпотентно - состояние машины с «hello! \ N», записанной на его устройство вывода, не совпадает с состоянием машины с «hello!\ nhello! \ n "записано на его устройство вывода.Я думаю, также ясно, что в этом случае ваша функция F является идемпотентной (хотя она не является «чистой», поскольку ее возвращаемое значение зависит от состояния, отличного от его формальных параметров, и, следовательно, это не просто реализацияматематическая функция), а ваша функция F2 не идемпотентна.Если бы test были неизменными, то мы могли бы разумно начать описывать F как чистый.F2 тогда будет недействительным.

Насколько я знаю, когда compscis говорит об идемпотентности в императивных языках, они обычно говорят о том, являются ли функции состояний машины, определенные в случае 2, идемпотентными или нет.,Но использование может варьироваться - если процедура чиста, то они могут говорить о том, является ли математическая функция, которую она представляет, идемпотентной.В чистом функциональном языке нет никакого состояния машины, о котором можно говорить, поэтому случай 2 был бы неуместным, и любое использование термина «идемпотент» по отношению к функции должно быть случаем 1. Функции в чисто функциональных языках всегда похожи на математические функции.

1 голос
/ 30 января 2014

Я также пытался выяснить, что на самом деле означает идемпотентность, и я понял, что существует множество определений идемпотентности.Далее следуют два определения: определение математических функций и функций программирования или определение информатики.

Математическое определение : f(f(x)) = f(x) for any value x.Другими словами, функция является идемпотентной, если эффект функции инвариантен относительно композиции.

Определение информатики : Функция является идемпотентной, если "побочный эффект от N> 0 идентичных запросовтакой же, как для одного запроса ".Другими словами, функция является идемпотентной, если эффект инвариантен относительно количества вызовов.

Например, возьмите функцию приращения, определенную как int f(int x) { return x+1; }.Эта функция потерпит неудачу в математическом определении, поскольку она не является инвариантной относительно композиции, потому что f (f (x))! = F (x).С другой стороны, это соответствует определению информатики, потому что, как упоминал Стив Маклеод,

int result1 = f(x);
// ... some arbitrary code
int result2 = f(x);
assert(result1 == result2);

Теперь, возвращаясь к вашему вопросу, является ли F () в вашем примере идемпотентным?Я говорю да, F () идемпотентен, но последовательность вызовов может не быть.Согласно определению идемпотентности протокола HTTP / 1.1: « возможно, последовательность из нескольких запросов не идемпотентна, даже если все методы, выполняемые в этой последовательности, являются идемпотентными ».

Это возможно, потому что вы должны рассматривать состояние программы как скрытый параметр функции F ().Например, рассмотрим примерную последовательность запросов F (), F (), F2 (), F ().Последний запрос F () не даст тот же результат, что и первые два, но это нормально, потому что запрос не был идентичным.Вы должны рассматривать состояние программы как скрытый параметр для функции, и в последнем запросе состояние состояло в том, что x был равен новому случайному значению, но в первых запросах состояние x было изначально нулевым.

Источники:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...