Ссылочная прозрачность - Referential transparency - Wikipedia

Ссылочная прозрачность и ссылочная непрозрачность являются свойствами частей компьютерные программы. An выражение называется ссылочно прозрачным, если он может быть заменены с соответствующим ему значением (и наоборот) без изменения поведения программы.[1] Для этого требуется, чтобы выражение было чистый, то есть значение выражения должно быть одинаковым для одних и тех же входных данных, а его оценка не должна иметь побочные эффекты. Выражение, которое не является ссылочно прозрачным, называется ссылочно непрозрачным.

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

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

История

Эта концепция, похоже, возникла в Альфред Норт Уайтхед и Бертран Рассел с Principia Mathematica (1910–13).[2] Он был принят в аналитическая философия к Уиллард Ван Орман Куайн. В §30 Слово и объект (1960) Куайн дает следующее определение:

Способ включения φ является ссылочно прозрачным, если всякий раз, когда вхождение сингулярного термина t является чисто ссылочным в термине или предложении ψ (t), оно является чисто ссылочным также и в содержащем его термине или предложении φ (ψ (t)).

Термин появился в его современном использовании в компьютерных науках при обсуждении переменные в языки программирования, в Кристофер Стрейчи оригинальный набор конспектов лекций Фундаментальные концепции языков программирования (1967). В конспектах лекции упоминается Куайн. Слово и объект в библиографии.

Примеры и контрпримеры

Если все функции, участвующие в выражении, чистые функции, то выражение референциально прозрачное.

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

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

Арифметические операции ссылочно прозрачны: 5 * 5 можно заменить на 25, например. Фактически, все функции в математическом смысле референциально прозрачны: грех (х) прозрачен, так как всегда дает одинаковый результат для каждого конкретного Икс.

Переназначения не прозрачны. Например, C выражение х = х + 1 изменяет значение, присвоенное переменной Икс. Предполагая Икс изначально имеет ценность 10, две последовательные оценки выражения дают, соответственно, 11 и 12. Понятно, что замена х = х + 1 либо с 11 или же 12 дает программу с другим значением, поэтому выражение не является прозрачным по ссылкам. Однако вызов такой функции, как int плюс один(int Икс) { возвращаться Икс + 1; } является прозрачным, поскольку он не будет неявно изменять вход x и, следовательно, не имеет такого побочные эффекты.

сегодня() не является прозрачным, как если бы вы оценили его и заменили его значением (скажем, «1 января 2001 г.»), вы не получите того же результата, что и при запуске его завтра. Это потому, что это зависит от государственный (Дата).

На языках без побочных эффектов, например Haskell, мы можем заменить равными равными: т.е. если х == у тогда f (x) == f (y). Это свойство также известно как неотличимые идентичности. Такие свойства не обязательно должны соблюдаться для языков с побочными эффектами. Даже в этом случае важно ограничить такие утверждения так называемым оценочным равенством, то есть равенством терминов, проверенных системой, не включая определяемую пользователем эквивалентность для типов. Например, если B f (A x) и тип А отвергает понятие равенства, например если все члены равны, то можно иметь х == у и все же найти е (х)! = е (у). Это потому, что такие системы, как Haskell не проверяйте, что функции, определенные для типов с определяемыми пользователем отношениями эквивалентности, правильно определены в отношении этой эквивалентности. Таким образом, ссылочная прозрачность ограничена типами без отношений эквивалентности. Расширение ссылочной прозрачности до определяемых пользователем отношений эквивалентности может быть выполнено, например, с типом идентичности Мартина-Лофа, но требует системы с зависимым типом, такой как в Агда, Coq или же Идрис.

В отличие от императивного программирования

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

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

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

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

Другой пример

В качестве примера давайте воспользуемся двумя функциями, одна из которых является ссылочно прозрачной, а другая - ссылочной непрозрачной:

int грамм = 0;int rt(int Икс) {  возвращаться Икс + 1;}int ро(int Икс) {  грамм++;  возвращаться Икс + грамм;}

Функция rt является ссылочно прозрачным, что означает, что если х == у тогда rt (x) == rt (y). Например, rt (6) = 7. Однако мы не можем сказать ничего подобного о ро потому что он использует изменяемую глобальную переменную.

Ссылочная непрозрачность ро усложняет рассуждение о программах. Например, предположим, что мы хотим обсудить следующее утверждение:

int я = ро(Икс) + ро(у) * (ро(Икс) - ро(Икс));

Может возникнуть соблазн упростить это утверждение до следующего:

int я = ро(Икс) + ро(у) * 0;int я = ро(Икс) + 0;int я = ро(Икс);

Однако это не сработает для ро потому что каждое появление ro (x) оценивается в другое значение. Помните, что возвращаемое значение ро основан на глобальном значении, которое не передается и которое изменяется при каждом вызове ро. Это означает, что математические тождества, такие как ИксИкс = 0 больше не держать.

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

Однако для упрощения утверждения можно использовать более сложный анализ:

int tmp = грамм; int я = Икс + tmp + 1 + (у + tmp + 2) * (Икс + tmp + 3 - (Икс + tmp + 4)); грамм = грамм + 4;int tmp = грамм; int я = Икс + tmp + 1 + (у + tmp + 2) * (Икс + tmp + 3 - Икс - tmp - 4)); грамм = грамм + 4;int tmp = грамм; int я = Икс + tmp + 1 + (у + tmp + 2) * (-1); грамм = грамм + 4;int tmp = грамм; int я = Икс + tmp + 1 - у - tmp - 2; грамм = грамм + 4;int я = Икс - у - 1; грамм = грамм + 4;

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

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

Смотрите также

Рекомендации

  1. ^ Джон С. Митчелл (2002). Концепции языков программирования. Издательство Кембриджского университета. п.78.
  2. ^ Альфред Норт Уайтхед; Бертран Рассел (1927). Principia Mathematica. 1 (2-е изд.). Издательство Кембриджского университета. Здесь: с.665. По словам Куайна, термин происходит оттуда.

внешняя ссылка