В функциональном программировании ссылочная прозрачность обычно означает, что выражение в коде может быть заменено результатом выполнения этого кода (или чем-либо, имеющим такое же значение), при этом результаты выполнения всего кода не изменятся. Это означает, что алгоритм всегда должен возвращать одно и то же значение для данного аргумента без какого-либо другого эффекта. Эта концепция функционального программирования также применима и к императивному программированию, и может помочь сделать код любого программиста более понятным. Мы подробно перевели статью “What Is Referential Transparency?” издания SitePoint и адаптировали примеры кода с Java (которая используется в оригинале) на JavaScript.
Ссылочная прозрачность
Термин ссылочная прозрачность используется в математике, логике, лингвистике, философии и в программировании. В каждой из этих областей он имеет совершенно разные значения. Здесь мы будем иметь дело только с компьютерными программами, хотя и покажем аналогию с математикой (но не волнуйтесь — с достаточно простой математикой). Мы рассмотрим ссылочную прозрачность, используемую функциональными программистами.
Ссылочная прозрачность в математике
В математике ссылочная прозрачность — это свойство выражений, которые могут быть заменены другими выражениями, имеющими такое же значение, без какого-либо изменения результата. Рассмотрим следующий пример:
x = 2 + (3 * 4)
Мы можем заменить подвыражение (3 * 4) любым другим выражением, имеющим то же значение, при этом не изменяя результат (значение x). Наиболее очевидное выражение, которое следует использовать, конечно же 12:
x = 2 + 12
При этом мы могли использовать любое другое выражение, имеющее значение 12 (возможно (5 + 7)), не боясь изменения результата. Как следствие, часть этого выражения — (3 * 4), имеет ссылочную прозрачность.
Мы можем заменить и выражение 2 + 12 другим выражением, имеющим то же значение — так, чтобы оно оставалось ссылочно-прозрачным:
x = 14
Читайте также:
Системы типов в языке — какие бывают и чем отличаются
Ссылочная прозрачность в программировании
В программировании ссылочная прозрачность применяется, соответственно, к программам. Поскольку они обычно состоят из подпрограмм, которые сами являются программами, это применимо и к этим подпрограммам. При этом они могут быть представлены в том числе и методами. Это означает, что эти процедуры могут быть ссылочно-прозрачными — особенно когда вызов методов может быть заменен их возвращаемым значением.
const add = (a, b) => a + b;
const mult = (a, b) => a * b;
const x = add(2, mult(3, 4));
В этом примере функция mult является ссылочно-прозрачной, потому что любой ее вызов может быть заменен соответствующим возвращаемым значением. Это можно увидеть, заменив mult(3, 4) на 12:
const x = add(2, 12);
Таким же образом add(2, 12) можно заменить на возвращаемое значение 14.
const x = 14;
Эти изменения не повлияют на результат работы программы, что бы она не выполняла. Обратите внимание, что вообще мы могли бы использовать любое другое выражение, имеющее аналогичное значение — это свойство очень полезно при рефакторинге.
С другой стороны, рассмотрите следующую программу:
const add = (a, b) => {
const result = a + b;
console.log(`Returning ${result}`);
return result;
};
Замена вызова add возвращаемым значением изменит результат работы программы, поскольку сообщение больше не будет печататься с помощью console.log. В этом случае замена просто удалит побочный эффект, но в других случаях она может изменить значение, которое возвращается алгоритмом.
const getFibsNext = () => {
let previous = -1;
let last = 1;
const next = () => {
last = previous + (previous = last);
return previous + last;
}
return next;
};
const printFibs = (limit) => {
const next = getFibsNext();
for (let i = 0; i < limit; i += 1) {
console.log(next());
}
};
printFibs(10);
Здесь функция next не может быть заменена чем-либо, даже если оно имело бы такое же значение. Это связано с тем, что эта функция предназначена для возврата абсолютно разных значений при каждом вызове.
Использование таких конструкций без ссылочной прозрачности требует особого внимания, чтобы не пропустить изменяемое состояние, участвующее в вычислении. Функциональный стиль избегает таких методов в пользу их ссылочно-прозрачных версий.
Ссылочная прозрачность в императивном программировании
Функции используются как в императивном, так и в функциональном (декларативном) программировании. Несмотря на то, что функциональное программирование использует только функции, в императивном программировании также используются:
— чистые функции: методы, возвращающие значения, и не имеющие других эффектов.
— чистые эффекты: методы, не возвращающие ничего, кроме изменения чего-то вне их.
— функции с побочными эффектами: методы, возвращающие значение, и при этом что-либо изменяющие вне их.
Читайте также:
DevOps — что это такое и почему эти практики меняют мир разработки уже сейчас
Как мы все знаем, рекомендуется избегать функций с побочными эффектами. Это оставляет императивным программистам возможность использовать или чистые функции, или чистые эффекты. Таким образом, ссылочная прозрачность является мощным инструментом для императивных программистов, который упрощает понимание программ, а также упрощает их тестирование.
Итог
Ссылочная прозрачность означает, что вызов функции может быть заменен ее значением, либо другим ссылочно-прозрачным вызовом с тем же результатом. Это делает каждую подпрограмму независимой, что значительно упрощает модульное тестирование и рефакторинг. Кроме того, такие ссылочно-прозрачные программы легче читать и понимать — это одна из причин, почему код, написанный в функциональном стиле, нуждается в меньшем количестве комментариев.
____________________________
Другие материалы о программировании читайте в блоге Хекслета.