Прозорість посилань (інформатика)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Прозорість посилань і непрозорість посилань — це властивості частин комп'ютерних програм. Вираз називають прозорим за посиланнями, якщо його можна замінити на його значення і це не вплине на поведінку програми[1]. Для цього потрібно аби вираз був чистим - його значення повинно бути однаковим для однакових аргументів і обчислення не повинно створювати побічних ефектів. Вираз який не є прозорим за посиланнями називають непрозорим за посиланнями.

В математиці всі функції прозорі за посиланнями, за визначенням математичної функції. Проте, в програмуванні це не завжди так, і часто для уникнення плутанити використовуються терміни процедура та метод. Ключовою характеристикою функційного програмування є те, що воно дозволяє лише прозорі за посиланням функції.

Важливість прозорості посилань полягає в тому, що вони дозволяють програмісту та компілятору робити здогади про поведінку програми. Це може допомогти в доведенні коректності[en], спрощенні алгоритму, допомагає при зміні коду без отримання нових помилок або оптимізації коду за допомогою мемоізації, усунення спільних підвиразів, лінивого обчислення або паралелізації.

Історія[ред. | ред. код]

Поняття ймовірно походить з Principia Mathematica (1910–13) Альфреда Норта Вайтгеда та Бертрана Рассела.[2] Його ввів у аналітичну філософію Віллард Ван Орман Квайн.

У сучасній інформатиці термін з'явився під час обговорення змінних у впливовій серії конспектів лекцій Кристофера Стречи[en] Fundamental Concepts in Programming Languages[en] (1967). Конспект посилався на Word and Object Квайна в бібліографії.

Приклади й контрприклади[ред. | ред. код]

Якщо в виразі задіяні лише чисті функції, тоді вираз буде прозорим за посиланнями. Також, деякі нечисті функції можуть бути використані у виразі, якщо їх значення не впливають на значення виразу та їх побічні ефекти незначимі.

Візьмемо функцію, що не приймає параметрів і повертає дані, введені з клавіатури. Припустимо, її виклик такий: GetInput(). Значення повернуте функцією GetInput() залежить від вводу користувача, отже різні виклики GetInput() з однаковими параметрами (порожній список) можуть повертати різні значення. Звідси, GetInput() ані детермінована, ані прозора за посиланнями.

Витонченіший приклад — функція, що використовує глобальну змінну (змінну з динамічною областю видимості або лексичне замикання), щоб полегшити собі обчислення результату. Через те, що ця змінна не передається як параметр, але може бути змінена, результати послідовних викликів можуть відрізнятись, навіть якщо параметри тотожні. В чистому функційному програмуванні використовується підхід єдиного присвоєння, тобто змінні після присвоєння їм значень стають незмінними об'єктами.

Арифметичні операції прозорі за посиланнями: 5*5 можна замінити на 25. В дійсності, всі функції прозорі за посиланнями в математичному сенсі: sin(x) прозора, бо завжди повертає однакове значення для певного x.

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

В більшості мов[яких?] вираз print("Вітаю, світе!") не прозорий, бо його заміна на значення, що повертається, змінює поведінку програми, бо «Вітаю, світе!» не надрукується.

today() теж не прозора, бо видає різні значення кожного нового дня.

Відмінність від імперативного програмування[ред. | ред. код]

Якщо заміна виразу на його значення дійсна тільки в певній точці виконання програми, тоді цей вираз не прозорий за посиланнями. Визначення і впорядкування цих точок перебігу (англ. sequence point) це теоретичні підвалини імперативного програмування і частина семантики імперативних мов програмування.

Однак через можливість обчислення виразів прозорих за посиланнями будь-коли, необов'язково визначати точки перебігу й взагалі будь-які гарантії послідовності виконання. Програмування виконане на такий лад називається чисто функційним програмуванням.

Однією з переваг написання коду з прозорими посиланнями є те, що розумному компілятору легше виконувати статичний аналіз коду і використовувати кращі оптимізації. Наприклад, у випадку С присутнє погіршення швидкодії через додавання до тіла циклу дорогої, в сенсі виконання, функції, навіть якщо виклик функції можна винести за тіло циклу без зміни результату програми. Програміст змушений робити ручні правки, які можливо позначаться на зручності читання коду. А якщо компілятор в змозі визначити, що виклик функції прозорий за посиланнями, він може здійснити це перетворення автоматично.

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

У випадку прозорості посилань немає різниці між посиланням на об'єкт і самим об'єктом. Інакше така різниця може бути легко введена й використана.

Примітки[ред. | ред. код]

  1. John C. Mitchell (2002). Concepts in Programming Languages. Cambridge University Press. с. 78.
  2. Alfred North Whitehead; Bertrand Russell (1927). Principia Mathematica. Т. 1 (вид. 2nd). Cambridge University Press. На сторінці 665. Згідно з Квайном, термін походить звідти.

Посилання[ред. | ред. код]