Незмінюваність або незмінність - це не поняття, які мають сенс у функціональному програмуванні.
Обчислювальний контекст
Це дуже гарне запитання, яке є цікавим поданням (а не дублікатом) до іншого недавнього: Яка різниця між призначенням, оцінкою та прив’язкою до імені?
Натомість, відповідаючи на ваші твердження по черзі, я намагаюся тут дати вам структурований огляд того, що є на ставки.
Є кілька питань, на які слід відповісти, зокрема:
Що таке модель обчислення та які поняття мають сенс для даної моделі
Яке значення слів, які ви вживаєте, і як це залежить від контексту
Функціональний стиль програмування здається нерозумним, тому що ви бачите його з обов'язковим оком програміста. Але це інша парадигма, і ваші імперативні поняття та сприйняття чужі, поза місцем. У укладачів таких забобонів немає.
Але кінцевий висновок полягає в тому, що можна писати програми суто функціональним способом, в тому числі і для машинного навчання, продумане функціональне програмування не має концепції зберігання даних. Здається, я не згоден з цим питанням з іншими відповідями.
Сподіваємось, мало хто буде зацікавлений, незважаючи на тривалість цієї відповіді.
Обчислювальні парадигми
Питання стосується функціонального програмування (він же аплікативного програмування), специфічної моделі обчислення, теоретичним і найпростішим представником якої є лямбда-числення.
Якщо ви залишаєтесь на теоретичному рівні, існує багато моделей обчислень: машина Тьюрінга (ТМ), машина ОЗУ та інші , обчислення лямбда, комбінаційна логіка, теорія рекурсивних функцій, системи напівтуї тощо. Більш потужні обчислювальні системи Моделі виявилися рівнозначними з точки зору того, що вони можуть вирішити, і в цьому полягає суть
тези Церкви-Тьюрінга .
Важливою концепцією є зменшення моделей одна до одної, що є основою для встановлення еквівалентів, які призводять до тези Церкви-Тьюрінга. З точки зору програмістів, скорочення однієї моделі до іншої - це майже все, що зазвичай називають компілятором. Якщо ви вважаєте логічне програмування своєю моделлю обчислень, воно сильно відрізняється від моделі, що надається ПК, який ви купили в магазині, і компілятор перекладає програми, написані мовою логічного програмування, в обчислювальну модель, представлену вашим ПК (досить багато комп'ютер оперативної пам'яті).
Однак це не означає, що обидві моделі роблять речі однаковими способами, або що поняття, яке має значення для однієї, може бути передане як таке іншому. Зазвичай крок обчислення в ТМ має мало відношення до (β-) крок відновлення в обчисленні лямбда, хоча вони є взаємоперекладними. Концепція оптимального оцінювання лямбда-експресії досить далека від питань складності в моделях ТМ.
На практиці мови програмування, які ми використовуємо, як правило, змішують поняття різного теоретичного походження, намагаючись це зробити так, щоб вибрані частини програми могли отримати користь від властивостей якоїсь моделі, де це доречно. Аналогічно, люди, що будують системи, можуть вибирати різні мови для різних компонентів, щоб вони найкраще відповідали мові.
Отже, ви рідко бачите парадигму програмування в чистому стані мовою програмування. Мови програмування все ще класифікуються відповідно до домінуючої парадигми, але на властивості мови можуть вплинути, коли задіяні поняття з інших парадигм, що часто розмиває відмінності та концептуальні проблеми.
Зазвичай такі мови, як Haskell та ML або CAML, вважаються функціональними, але вони можуть враховувати імперативну поведінку ... Інакше навіщо говорити про " суто функціональний підмножина "?
Тоді можна стверджувати, що ви можете зробити те чи інше в моїй мові функціонального програмування, але це насправді не відповідає на питання про функціональне програмування, коли воно покладається на те, що можна вважати позафункціональним.
Відповіді повинні бути точніше пов'язані з конкретною парадигмою, без зайвих.
Що таке змінна?
Ще одна проблема - використання термінології. У математиці змінна - це сутність, яка стоїть за невизначеним значенням у деякій області. Його використовують для різних цілей. Використовується в рівнянні, воно може означати будь-яке значення, таке, що рівняння перевірено. Це бачення використовується в логічному програмуванні під назвою " логічна змінна ", ймовірно, тому, що змінна назва вже мала інше значення при розробці логічного програмування.
У традиційному імперативному програмуванні змінна розуміється як якийсь контейнер (або місце пам'яті), який може запам'ятати подання значення і, можливо, отримати його поточне значення замінено на інше).
У функціональному програмуванні змінна має ту саму мету, яку вона виконує в математиці, як утримувач місць для певного значення, але вона повинна бути надана. У традиційному імперативному програмуванні цю роль насправді відіграє константа (не плутати з літералами, які визначаються значенням, вираженим позначеннями, характерними для даної області значень, такими як 123, true, ["abdcz", 3.14]).
Змінні будь-якого виду, а також постійні можуть бути представлені ідентифікаторами.
Імперативна змінна може змінити її значення, і це є основою для змінності. Функціональна змінна не може.
Мови програмування зазвичай дозволяють будувати більші об'єкти з менших мов.
Імперативні мови дозволяють таким конструкціям включати змінні, і саме це дає вам змінні дані.
Як читати програму
Програма є принципово абстрактним описом вашого алгоритму - якоюсь мовою, будь то прагматична конструкція чи парадигматично чиста мова.
В принципі, ви можете приймати кожне твердження за те, що воно повинно означати абстрактно. Тоді компілятор переведе це в якусь відповідну форму для виконання комп'ютера, але це не ваша проблема в першому наближенні.
Звичайно, реальність трохи суворіша, і часто добре мати деяке уявлення про те, що відбувається, щоб уникнути структур, з якими компілятор не знатиме, як впоратися для ефективного виконання. Але це вже оптимізація ... для яких компілятори можуть бути дуже хорошими, часто кращими, ніж програмісти.
Функціональне програмування та можливість зміни
Змінюваність ґрунтується на існуванні імперативних змінних, які можуть містити значення, які слід змінювати за призначенням. Оскільки їх не існує у функціональному програмуванні, все можна розглядати як непорушне.
Функціональне програмування має справу виключно зі значеннями.
Ваші перші чотири твердження про незмінність є здебільшого правильними, але описуючи з імперативом викладайте щось, що не є обов'язковим. Це трохи схоже на опис кольорів у світі, де кожен сліпий. Ви використовуєте концепції, чужі для функціонального програмування.
У вас є лише чисті значення, а масив цілих чисел - це чисте значення. Щоб отримати інший масив, який відрізняється лише одним елементом, ви повинні використовувати інше значення масиву. Зміна елемента - це лише поняття, яке не існує в цьому контексті. Можливо, у вас є функція, яка містить масив та деякі індекси як аргумент, і повертає результат, який є майже ідентичним масивом, який відрізняється лише там, де зазначено індексами. Але це все-таки значення незалежного масиву. Як представлені ці значення - це не ваша проблема. Можливо, вони багато "діляться" в імперативному перекладі на комп’ютер ... але це робота компілятора ... і ви навіть не хочете знати, для якої архітектури машини вона збирається.
Ви не копіюєте значення (це не має сенсу, це чуже поняття). Ви просто використовуєте значення, які існують у областях, визначених у вашій програмі. Або ви описуєте їх (як буквальні), або вони є результатом застосування функції до деяких інших значень. Ви можете дати їм ім'я (таким чином визначивши константу), щоб переконатися, що одне і те ж значення використовується в різних місцях програми. Зауважте, що застосування функції не повинно сприйматися як обчислення, а як результат застосування до заданих аргументів. Написання 5+2
чи написання 7
становить те саме. Що узгоджується з попереднім пунктом.
Немає імперативних змінних. Призначення неможливо. Ви можете прив'язувати імена лише до значень (для формування констант), на відміну від імперативних мов, де ви можете прив’язувати імена до призначуваних змінних.
Чи має це вартість у складності, абсолютно незрозуміло. З одного боку, ви посилаєтесь на складність стосується імперативних парадигм. Він не визначений як такий для функціонального програмування, якщо ви не вирішите прочитати свою функціональну програму як імперативну, що не є наміром дизайнера. Дійсно, функціональний погляд призначений для того, щоб не турбуватися про подібні проблеми та сконцентруватися на тому, що обчислюється. Це трохи схоже на специфікацію та реалізацію.
Компілятор повинен дбати про реалізацію та бути достатньо розумним, щоб найкращим чином адаптувати те, що потрібно зробити, до обладнання, яке це зробить, незалежно від того, що воно буде.
Я не кажу, що програмісти ніколи не турбуються про це. Я також не кажу, що мови програмування та технології компілятора настільки ж зрілі, як ми могли б їх побажати.
Відповідаючи на запитання
Ви не змінюєте наявне значення (чужорідне поняття), але обчислюєте нові значення, які відрізняються, де потрібно, можливо, маючи один додатковий елемент, це список.
Програма може отримати нові дані. Вся справа в тому, як ви це виражаєте мовою. Наприклад, ви можете вважати, що програма працює з одним конкретним значенням, можливо, необмеженим розміром, яке називається вхідним потоком. Це значення, яке повинно сидіти там (незалежно від того, це вже відомо повністю чи ні - це не ваша проблема). Тоді у вас є функція, яка повертає пару, що складається з першого елемента потоку та решти потоку.
Ви можете використовувати це для створення мереж комунікаційних компонентів суто прикладним способом (супроводи)
Машинне навчання - це ще одна проблема, коли вам доведеться акредити дані та змінювати значення. У функціональному програмуванні ви цього не робите: ви просто обчислюєте нові значення, які відповідно відрізняються відповідно до навчальних даних. Отримана машина також буде працювати. Що вас хвилює - це обчислення ефективності часу та простору. Але, знову ж таки, це інше питання, яким в ідеалі повинен займатися компілятор.
Заключні зауваження
З коментарів чи інших відповідей цілком зрозуміло, що мови практичного функціонування не є суто функціональними. Це відображення того факту, що наша технологія ще вдосконалюється, особливо це стосується компіляції.
Чи можна писати в суто додатковому стилі? Відповідь відома вже близько 40 років, і це "так". Сама мета денотаційної семантики, як вона з'явилася в 1970-х, полягала саме в тому, щоб перекласти (скласти) мови в суто функціональний стиль, який вважався математично краще зрозумілим і, таким чином, вважався кращим фундаментом для визначення семантики програм.
Цікавим аспектом є те, що імперативна структура програмування, включаючи змінні, може бути перетворена у функціональний стиль шляхом введення відповідних доменів значень, таких як сховище даних. І незважаючи на функціональний стиль, він залишається напрочуд схожим з кодом фактичних компіляторів, написаним в імперативному стилі.