Що означають терміни функціональне, декларативне та імперативне програмування?
Що означають терміни функціональне, декларативне та імперативне програмування?
Відповіді:
На момент написання цього запису голосні відповіді на цій сторінці є неточними та заплутаними щодо декларативного проти імперативного визначення, включаючи відповідь, що цитує Вікіпедію. Деякі відповіді співпадають з термінами по-різному.
Також зверніться до мого пояснення, чому програмування електронних таблиць є декларативним, незалежно від того, що формули мутують комірки.
Також кілька відповідей стверджують, що функціональне програмування повинно бути підмножиною декларативного. Від цього залежить, якщо ми будемо відрізняти "функцію" від "процедури". Давайте спочатку обробляємо імператив проти декларативних.
Визначення декларативного вираження
Тільки атрибут , який може можливо диференціювати декларативне вираження з імперативного вираження є посилальної прозорістю (RT) його подвираженія. Усі інші атрибути або поділяються між обома типами виразів, або походять від RT.
100% декларативна мова (тобто така, в якій всі можливі вирази є RT) не дозволяє (серед інших вимог RT) мутувати збережені значення, наприклад, HTML та більшість Haskell.
Визначення експресії RT
RT часто називають "відсутнім побічних ефектів". Термін " Ефекти " не має точного визначення, тому деякі люди не згодні з тим, що "відсутність побічних ефектів" є такою ж, як RT. RT має точне визначення .
Так як кожен суб-вираз концептуально виклик функції, RT вимагає, щоб виконання функції (тобто вираз (и) всередині функції, що викликається) не може отримати доступ до змінюваного стану, яке зовнішні функції ( Отримання доступу до змінним локальне стан є дозволено). Простіше кажучи, функція (реалізація) повинна бути чистою .
Визначення чистої функції
Чиста функція, як кажуть, не має "побічних ефектів". Термін " Ефекти " не має точного визначення, тому деякі люди не згодні.
Чисті функції мають такі атрибути.
Пам’ятайте, що RT застосовується до виразів (що включає виклики функцій), а чистота застосовується до (реалізації) функцій.
Незрозумілий приклад нечистих функцій, які створюють вирази RT, є одночасністю, але це тому, що чистота порушується на шарі абстракції переривання. Вам не потрібно цього знати. Для створення виразів RT ви викликаєте чисті функції.
Похідні ознаки RT
Будь-який інший атрибут, що цитується для декларативного програмування, наприклад, цитування з 1999 року, яке використовує Вікіпедія, або походить від RT, або поділяється з імперативним програмуванням. Таким чином доводячи, що моє точне визначення є правильним.
Зауважимо, незмінність зовнішніх значень - це підмножина вимог до RT.
Декларативні мови не мають зациклення керуючі структури, наприклад , for
і while
, так як з - за незмінності , умова циклу не зміниться.
Декларативні мови не виражають потоку управління, окрім вкладених порядкових функцій (також логічних залежностей), оскільки через незмінність інші варіанти порядку оцінювання не змінюють результат (див. Нижче).
Декларативні мови виражають логічні "кроки" (тобто вкладений порядок виклику функції RT), але чи кожен виклик функції є семантичним вищим рівнем (тобто "що робити"), не є вимогою декларативного програмування. Відмінність від імперативного полягає в тому, що через незмінність (тобто, загалом, RT), ці "кроки" не можуть залежати від стану, що змінюється, а лише реляційного порядку вираженої логіки (тобто порядку введення функцій викликів, так само суб-вирази ).
Наприклад, абзац HTML <p>
не може відображатися доти, поки не будуть оцінені під вирази (тобто теги) в абзаці. Не існує стану, що змінюється, лише залежність від порядку через логічну взаємозв'язок ієрархії тегів (введення суб-виразів, які є аналогічно вкладеними викликами функцій ).
Таким чином , існує похідна атрибут незмінності ( в більш загальному випадку РТ), що декларативні вирази, висловлюють тільки ті логічні відносини складових частин (тобто аргументів функції суб-експресії) , а не змінювані державні відносини.
Порядок оцінювання
Вибір порядку оцінки підвиразів може дати різний результат лише тоді, коли будь-який з викликів функції не є RT (тобто функція не є чистою), наприклад, деякий змінений стан, який знаходиться зовні функції, має доступ до функції.
Наприклад, якщо кілька вкладених виразів, наприклад f( g(a, b), h(c, d) )
, охоче і ледачі обчислення аргументів функції будуть давати ті ж результати , якщо функції f
, g
і h
є чистими.
Якщо функції f
, g
і h
не є чистими, то вибір порядку оцінки може дати інший результат.
Зауважте, вкладені вирази - це концептуально вкладені функції, оскільки оператори виразів - це лише виклики функцій, маскуються як унарний префікс, одинарний постфікс або двозначне позначення інфіксації.
Тангенціально, якщо все ідентифікатори, наприклад a
, b
, c
, d
, є непорушними всюди, стан зовнішнього по відношенню до програми не може бути доступно (наприклад , I / O), і немає ніякого руйнування рівня абстракції, то функції завжди чисті.
До речі, Haskell має інший синтаксис, f (g a b) (h c d)
.
Деталі замовлення на оцінку
Функція - це перехід стану (не змінне збережене значення) від входу до виходу. Для RT-композицій викликів до чистих функцій порядок виконання цих переходів стану не залежить. Перехід стану кожного виклику функції не залежить від інших через відсутність побічних ефектів і принципу, що функція RT може бути замінена кешованим значенням . Щоб виправити поширене оману , чистий монадійний склад завжди є декларативним і незважаючи на те, що IO
монада Хаскелла, мабуть, нечиста і, таким чином, є обов'язковим для зміни World
стану, що знаходиться поза програмою (але в сенсі застереження нижче, побічні ефекти поодинокі).
Швидке оцінювання означає, що аргументи функцій оцінюються до виклику функції, а ледаче оцінювання означає, що аргументи не оцінюються до тих пір, поки (і якщо) вони не отримають доступ до функції.
Визначення : параметри функції оголошуються на сайті визначення функції , а аргументи функції подаються на сайті виклику функції . Знайти різницю між параметром і аргументом .
Концептуальна, всі вирази (композиція) виклики функцій, наприклад , константа функція без входів, унарні функції з одним входом, бінарні оператори інфіксне функцій з двома входами, конструкторами є функціями, а також заяви навіть управління (наприклад if
, for
, while
) можна моделювати за допомогою функцій. Порядок , що цей аргумент функція (не плутати з вкладеною функцією порядку виклику) оцінюються не оголошений синтаксисом, наприклад , f( g() )
може з готовністю оцінити g
те f
на g
результаті «s або він може оцінити f
і тільки ліниво оцінити , g
коли його результат потрібен в f
.
Застереження, відсутність повної мови Тюрінга (тобто, що дозволяє необмежену рекурсію) є ідеально декларативною, наприклад, ледача оцінка вводить пам'ять та час індетермінізму. Але ці побічні ефекти, обумовлені вибором порядку оцінювання, обмежуються споживанням пам'яті, часом виконання, затримкою, неприпиненням і зовнішнім гістерезисом, таким чином, зовнішньою синхронізацією.
Функціональне програмування
Оскільки декларативне програмування не може мати циклів, то єдиним способом ітерації є функціональна рекурсія. Саме в цьому сенсі функціональне програмування пов'язане з декларативним програмуванням.
Але функціональне програмування не обмежується декларативним програмуванням . Функціональна композиція може бути протиставлена підтипу , особливо стосовно проблеми вираження , де розширення може бути досягнуто шляхом додавання підтипів або функціональної декомпозиції . Розширення може бути поєднанням обох методологій.
Функціональне програмування зазвичай робить функцію об'єктом першого класу, тобто тип функції може з'являтися в граматиці в будь-якому іншому місці. Підсумок полягає в тому, що функції можуть вводити та функціонувати над функціями, забезпечуючи таким чином роз'єднання проблем, підкреслюючи склад функції, тобто розділяючи залежності між підрахунками детермінованих обчислень.
Наприклад, замість написання окремої функції (та використання рекурсії замість циклів, якщо функція також повинна бути декларативною) для кожної нескінченної кількості можливих спеціалізованих дій, які можна було б застосувати до кожного елемента колекції, функціональне програмування використовує багаторазову ітерацію функції, наприклад map
, fold
, filter
. Ці ітераційні функції вводять першокласну спеціалізовану функцію дії. Ці ітераційні функції повторюють збір та викликають функцію введення спеціалізованих дій для кожного елемента. Ці функції дій є більш стислими, оскільки їм більше не потрібно містити циклічні заяви, щоб повторити колекцію.
Однак зауважте, що якщо функція не є чистою, то це дійсно процедура. Ми можемо стверджувати, що функціональне програмування, яке використовує нечисті функції, насправді є процедурним програмуванням. Таким чином, якщо ми погоджуємось, що декларативні вирази є RT, то можна сказати, що процедурне програмування не є декларативним програмуванням, і, таким чином, ми можемо стверджувати, що функціональне програмування завжди є RT і повинно бути підмножиною декларативного програмування.
Паралелізм
Ця функціональна композиція з першокласними функціями може виражати глибину в паралелізмі , відокремлюючи незалежну функцію.
Принцип Брента: обчислення з роботою w і глибиною d можуть бути реалізовані в p-процесорі PRAM за час O (макс. (Ш / р, d)).
І паралельність, і паралелізм також вимагають декларативного програмування , тобто незмінність і RT.
То звідки взялося це небезпечне припущення, що паралелізм == Паралельність? Це природний наслідок мов із побічними ефектами: коли у вашої мови є побічні ефекти скрізь, то будь-коли, коли ви намагаєтесь робити більше, ніж одно, у вас, по суті, виникає недетермінізм, викликаний переплетенням ефектів від кожної операції . Отже, в мовах побічних ефектів єдиний спосіб отримати паралелізм - це паралельність; тому не дивно, що ми часто бачимо цих двох переплутаних.
Зауважте, порядок оцінювання також впливає на припинення та ефективність функціональних композицій.
Гострий (CBV) та ледачий (CBN) - це категоричні поєдинки [ 10 ], оскільки вони змінили порядок оцінки, тобто, чи оцінюються спочатку зовнішня чи внутрішня функції відповідно. Уявіть перевернуте дерево, а потім нетерплячий оцінює з гілки дерева функцій підведення ієрархії гілок до стовбура функції верхнього рівня; тоді як ледачий оцінює від стовбура до кінця гілки. Eager не має кон'юнктивних продуктів ("і", a / k / категоричні "продукти"), а ледачий не має диз'юнктивних копродуктів ("або", a / k / категоричні "суми") [ 11 ].
Продуктивність
Нетерплячий
Як і у випадку неприпинення, нетерплячий надто охоче поєднується з функціональним складом, тобто композиційна контрольна структура виконує непотрібну роботу, яка не робиться з ледачим. До прикладу , бажаючи охоче і надмірно відображає весь список до булевої, коли вона складається зі складкою , яка закінчується на перший справжній елементі.
Ця непотрібна робота є причиною заявленого «до» додаткового логічного коефіцієнта в послідовності часової складності прагнення проти ледачих, як з чистими функціями. Рішенням є використання функторів (наприклад, списків) з ледачими конструкторами (тобто охочих з необов'язковими лінивими продуктами), оскільки з нетерпінням нетерпіння нетерпіння походить від внутрішньої функції. Це пояснюється тим, що продукти мають конструктивні типи, тобто індуктивні типи з початковою алгеброю на початковій точці [ 11 ]
Ледачий
Як і у випадку неприпинення, лінивий занадто лінивий з диз'юнктивним функціональним складом, тобто коіндуктивна остаточність може виникнути пізніше, ніж це необхідно, внаслідок чого виникає як непотрібна робота, так і недетермінованість запізнення, що не буває у бажаючих [ 10 ] [ 11 ] . Прикладами остаточності є виключення стану, часу, неприпинення та виконання. Це імперативні побічні ефекти, але навіть у чистій декларативній мові (наприклад, Haskell) в імперативному монаді IO є стан (зауважте: не всі монади є імперативними!), Що маються на увазі у виділенні простору, а терміни - стан відносно імперативу Реальний світ. Використання лінивих навіть із необов'язковими охочими копродуктами просочує "лінь" у внутрішні копродукти, адже при ліні лінь неправильність походить від зовнішньої функції(див. приклад у розділі Неприпинення, де == - функція зовнішнього бінарного оператора). Це відбувається тому, що копродукти обмежені кінцевістю, тобто коіндуктивними типами з кінцевою алгеброю на кінцевому об'єкті [ 11 ].
Lazy викликає індетермінізм у проектуванні та налагодженні функцій для затримки та простору, налагодження яких, ймовірно, виходить за межі можливостей більшості програмістів, через дисонанс між заявленою ієрархією функцій та порядком виконання часу оцінювання. Ледачі чисті функції, оцінені з нетерпінням, можуть потенційно ввести раніше небачені неприпинення під час виконання. І навпаки, жадібні чисті функції, оцінені ледачими, можуть потенційно внести невидимий раніше простір та затримку затримки під час виконання.
Неприпинення
Під час компіляції через проблему зупинки та взаємної рекурсії мовою повного Тюрінга функції, як правило, не можуть бути гарантовано припинені.
Нетерплячий
З нетерпінням, але не лінивим, сполучення Head
"і" Tail
, якщо Head
або Tail
не припиняється, то відповідно List( Head(), Tail() ).tail == Tail()
або List( Head(), Tail() ).head == Head()
є, або не відповідає дійсності, оскільки лівий бік не робить, а правий - припиняється.
В той час, як ліниві обидві сторони закінчуються. Таким чином, охоче надто охоче поєднується з продуктами, і не припиняється (включаючи винятки з виконання) в тих випадках, коли це не потрібно.
Ледачий
Якщо ледачий, але не прагнутий, для диз'юнкції 1
"або" 2
, якщо f
не закінчується, то List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail
це неправда, тому що лівий бік закінчується, а правий - ні.
Тоді як жоден із сторін не припиняється, тому тест рівності ніколи не досягається. Таким чином, ледачий занадто лінивий з диз'юнктивними копродуктами, і в цих випадках не вдається припинити (включаючи винятки з виконання), виконавши більше роботи, ніж бажав би.
[ 10 ] Декларативні продовження та категорична подвійність, Філінський, розділи 2.5.4 Порівняння CBV та CBN та 3.6.1 CBV та CBN у SCL.
[ 11 ] Декларативні продовження та категорична подвійність, Філінський, розділи 2.2.1 Продукти та копродукти, 2.2.2 Термінали та початкові об'єкти, 2.5.2 КБВ із лінивими продуктами та 2.5.3 КБН із охочею копродукцією.
Не існує насправді жодного неоднозначного об’єктивного визначення для них. Ось як я їх би визначив:
Імператив - Основна увага на те , що кроки , які комп'ютер повинен прийняти , а не те , що комп'ютер буде робити (колишній C, C ++, Java.).
Декларативний. Основна увага приділяється тому, що повинен робити комп'ютер, а не тому, як це робити (наприклад, SQL).
Функціональний - підмножина декларативних мов, що має велику увагу на рекурсії
імперативний та декларативний опис двох протилежних стилів програмування. Імперативом є традиційний підхід "поетапний рецепт", тоді як декларативний більше "це те, що я хочу, тепер ви вирішите, як це зробити".
ці два підходи зустрічаються впродовж програмування - навіть з тією ж мовою та однією і тією ж програмою. загалом декларативний підхід вважається кращим, оскільки він позбавляє програміста від необхідності вказувати стільки деталей, а також менше шансів на помилки (якщо ви описуєте потрібний результат, а деякі добре перевірені автоматичні процеси можуть працювати назад від цього до визначте кроки, тоді ви можете сподіватися, що речі надійніші, ніж потрібно вказувати кожен крок вручну).
з іншого боку, імперативний підхід дає більш низький рівень контролю - це "підхід мікроменеджера" до програмування. і це може дозволити програмісту використовувати знання про проблему, щоб дати більш ефективну відповідь. тому незвично, що деякі частини програми написані в більш декларативному стилі, але для критично важливих для швидкості частин важливіше.
як ви можете собі уявити, мова, якою ви користуєтесь для написання програми, впливає на те, наскільки декларативними ви можете бути - мова, яка має вбудовані "розумні" для розробки того, що робити, даючи опис результату, дозволить набагато декларативніше підхід, ніж той, де програмісту потрібно спочатку додати такий вид інтелекту з імперативним кодом, перш ніж мати можливість згодом створити декларативний рівень. наприклад, така мова, як prolog, вважається дуже декларативною, оскільки вона має вбудований процес, який шукає відповіді.
поки що ви помітите, що я не згадав про функціональне програмування. це тому, що це термін, значення якого не відразу пов'язане з двома іншими. в самому простому, функціональному програмуванні означає, що ви використовуєте функції. зокрема, ви використовуєте мову, яка підтримує функції як "значення першого класу" - це означає, що ви можете не тільки писати функції, але й можете писати функції, які записують функції (які записують функції, які ...), і передавати функції в функції. коротше - функції такі ж гнучкі і поширені, як речі, такі як рядки і числа.
тоді може здатися дивним, що функціональне, імперативне та декларативне часто згадується разом. причина цього - наслідок виведення ідеї функціонального програмування "до крайності". функція, в чистому сенсі - це щось із математики - свого роду "чорна скринька", яка приймає певний вклад і завжди дає однаковий результат. і така поведінка не вимагає зберігання змінних змінних. тож якщо ви розробляєте мову програмування, метою якої є реалізація дуже чистої, математично впливаючої ідеї функціонального програмування, ви в кінцевому підсумку відкидаєте ідею цінностей, які можуть змінюватися (у певному, обмеженому технічному сенсі).
і якщо ви це зробите - якщо обмежите, як змінні можуть змінюватися, - майже випадково ви змушуєте програміста писати програми, які є більш декларативними, тому що значна частина імперативного програмування описує, як змінюються змінні, і ви більше не можете. зробити це! тож виявляється, що функціональне програмування, зокрема, програмування на функціональній мові, - як правило, дає більше декларативного коду.
підсумовуючи, тоді:
імперативний та декларативний - це два протилежних стилі програмування (однакові назви використовуються для мов програмування, які заохочують ці стилі)
функціональне програмування - це стиль програмування, коли функції стають дуже важливими і, як наслідок, зміна значень стає менш важливою. обмежена здатність вказувати зміни значень примушує декларативніший стиль.
тому "функціональне програмування" часто описується як "декларативне".
Коротко:
Імперативний мову specfies ряд інструкцій , які комп'ютер виконує в послідовності (зробити це, то зробити це).
Декларативний мову оголошує набір правил про те, що результати повинні бути результатом яких входів (наприклад, якщо у вас є, то результат B). Двигун застосує ці правила до входів і дасть вихід.
Функціональний мова оголошує набір математичних / логічних функцій , які визначають , як вхід переводяться на вихід. напр. f (y) = y * y. це тип декларативної мови.
Імператив: як досягти нашої мети
Take the next customer from a list.
If the customer lives in Spain, show their details.
If there are more customers in the list, go to the beginning
Декларативне: чого ми хочемо досягти
Show customer details of every customer living in Spain
Імперативне програмування означає будь-який стиль програмування, де ваша програма побудована з інструкцій, що описують, як будуть відбуватися операції, виконані комп'ютером .
Декларативне програмування означає будь-який стиль програмування, де ваша програма описує проблему чи рішення, але не чітко вказує, як буде виконуватися робота .
Функціональне програмування - це програмування шляхом оцінки функцій та функцій функцій ... Оскільки (строго визначене) функціональне програмування означає програмування шляхом визначення вільних математичних функцій з побічними ефектами, тому це форма декларативного програмування, але це не єдиний вид декларативного програмування .
Логічне програмування (наприклад, у Prolog) - це ще одна форма декларативного програмування. Він включає обчислення, вирішуючи, чи є логічне твердження істинним (чи можна його задовольнити). Програма, як правило, являє собою низку фактів і правил - тобто опис, а не серія інструкцій.
Переписування термінів (наприклад, CASL) - це ще одна форма декларативного програмування. Він передбачає символічну трансформацію алгебраїчних термінів. Це повністю відрізняється від логічного програмування та функціонального програмування.
імператив - вирази описують послідовність дій, які потрібно виконати (асоціативні)
декларативний - вирази - це декларації, що сприяють поведінці програми (асоціативна, комутативна, ідентифікаційна, монотонна)
функціональний - вирази мають значення як єдиний ефект; семантика підтримує еквівалентне міркування
Оскільки я написав попередню відповідь, я сформулював нове визначення декларативного властивості, яке цитується нижче. Я також визначив імперативне програмування як подвійне властивість.
Це визначення перевершує те, що я надав у своїй попередній відповіді, оскільки воно є лаконічним і воно більш загальне. Але це може бути складніше, тому що наслідки теорем про незавершеність, застосовних до програмування та життя в цілому, люди важко загорнути.
Цитуване пояснення визначення обговорює роль чисто функціонального програмування в декларативному програмуванні.
Всі екзотичні типи програмування вписуються в наступну таксономію декларативної та імперативної, оскільки наступне визначення стверджує, що вони є дуальними.
Декларативний проти імперативного
Декларативне властивість є дивним, тупим і важким для того, щоб зафіксувати технічно точне визначення, яке залишається загальним і неоднозначним, оскільки це наївне уявлення про те, що ми можемо оголосити сенс програми (він же семантикою) програми, не маючи непередбачуваних побічних ефектів. Існує властива напруга між вираженням смислу та уникненням навмисних ефектів, і ця напруга насправді випливає із теорем про незавершеність програмування та нашого Всесвіту.
Занадто спрощене, технічно неточне і часто неоднозначне декларативне визначення як « що робити », а імператив як « як робити » . Неоднозначний випадок - " що " - це " як" " у програмі, яка виводить програму - компіляторі.
Очевидно, що необмежена рекурсія, яка робить мову Тьюрінга завершеною , є аналогічно і в семантиці - не тільки в синтаксичній структурі оцінки (він же оперативної семантики). Це логічно приклад, аналогічний теоремі Геделя - " будь-яка повна система аксіом також невідповідна ". Поміркуйте над суперечливою дивністю цієї цитати! Це також приклад, який демонструє, як вираз семантики не має доказуваної межі, тому ми не можемо довести 2, що програма (і аналогічно її семантика) зупиняється як теорема Холтінга.
Теореми про незавершеність випливають із фундаментальної природи нашого Всесвіту, яка, як сказано у Другому законі термодинаміки, « є ентропією (інакше числом незалежних можливостей) навіки має максимум ». Кодування та розробка програми ніколи не закінчуються - вона жива! - тому що вона намагається вирішити справжню потребу в світі, а семантика реального світу завжди змінюється і має тенденцію до більше можливостей. Люди ніколи не перестають відкривати нові речі (включаючи помилки в програмах ;-).
Щоб точно і технічно зафіксувати це вищезазначене бажане поняття всередині цього дивного всесвіту, який не має краю (подумайте про те, що немає "поза" нашої Всесвіту), потрібно чітке, але оманливе-не просте визначення, яке буде звучати неправильно, поки не буде пояснено глибоко.
Визначення:
Декларативне властивість є там, де може існувати лише один можливий набір висловлювань, який може виражати кожну конкретну модульну семантику.
Властивість імперативу 3 - це подвійне, коли семантика є непослідовною за складом та / або може бути виражена варіаціями множин тверджень.
Це визначення декларативного є виразно локальним за семантичним розмахом, тобто означає, що воно вимагає, щоб модульний семантичний зберігав своє послідовне значення незалежно від того, де і як воно є інстанційним та використаним у глобальному масштабі. Таким чином, кожен декларативно-модульний семантичний має бути внутрішньо ортогональним для всіх можливих інших - і не є неможливим (через теореми про незавершеність) глобальним алгоритмом чи моделлю для засвідчення послідовності, що також є пунктом " Більше не завжди краще " Роберта Харпера, професора комп'ютерних наук з університету Карнегі Меллона, одного з дизайнерів Standard ML.
Приклади цих модульних декларативною семантики включають категорії теорії функтори , наприклад , в
Applicative
, номінальний введення, просторів імен, названих полів і WRT на операційному рівні семантики то чисто функціонального програмування.Таким чином, добре розроблені декларативні мови можуть більш чітко виражати значення , хоча і з певною втратою загальності в тому, що можна виразити, але все ж виграють у тому, що можна виразити внутрішньою послідовністю.
Прикладом вищезгаданого визначення є набір формул у клітинках програми електронних таблиць - які, як очікується, не нададуть однакового значення при переміщенні до різних комірок стовпців та рядків, тобто змінених ідентифікаторів комірок. Ідентифікатори комірок є частиною і не є зайвою для передбачуваного значення. Таким чином, кожен результат електронної таблиці є унікальним wrt для ідентифікаторів комірок у наборі формул. Послідовним модульним семантичним в даному випадку є використання ідентифікаторів комірок як введення та виведення чистих функцій для формул комірок (див. Нижче).
Мова гіперрозмітки тексту (aka HTML) - мова для статичних веб-сторінок - є прикладом декларативної мови (але не зовсім 3 ), яка (принаймні до HTML 5) не мала можливості виражати динамічну поведінку. HTML - це, мабуть, найпростіша мова для вивчення. Для динамічної поведінки загальнозміцнюючу мову сценаріїв, наприклад JavaScript, зазвичай поєднували з HTML. HTML без JavaScript відповідає деклараційному визначенню, оскільки кожен іменний тип (тобто теги) зберігає своє послідовне значення під складом у межах правил синтаксису.
Конкуруючим визначенням декларативного є комутативні та ідентифікуючі властивості семантичних висловлювань, тобто те, що висловлювання можна переупорядковувати та дублювати, не змінюючи значення. Наприклад, висловлювання, що присвоюють значення названим полям, можна переупорядкувати та дублювати, не змінюючи значення програми, якщо ці імена є модульними wrt у будь-якому загальному порядку. Імена іноді означають порядок, наприклад, ідентифікатори комірок включають їх стовпці та рядки - переміщення підсумків на електронній таблиці змінює його значення. В іншому випадку ці властивості неявно вимагають глобальногопослідовність семантики. Взагалі неможливо розробити семантику висловлювань, щоб вони залишалися послідовними, якщо випадковим чином упорядковані чи дублюються, оскільки порядок та дублювання є властивими семантиці. Наприклад, висловлювання "Foo існує" (або конструкція) і "Foo не існує" (і знищення). Якщо вважати випадкову невідповідність ендемічною для передбачуваної семантики, то приймається це визначення як достатньо загальне для декларативної властивості. По суті це визначення є вакуумним як узагальнене визначення, оскільки воно намагається зробити ортогональну узгодженість семантикою, тобто спростувати той факт, що Всесвіт семантики динамічно не обмежена і не може бути захоплена глобальною парадигмою узгодженості.
Потрібні комутативні та ідентифікаційні властивості для (структурного порядку оцінки) операційної семантики нижнього рівня перетворюють оперативну семантику в декларативно локалізовану модульну семантику, наприклад, чисто функціональне програмування (включаючи рекурсію замість імперативних циклів). Тоді оперативний порядок деталей впровадження не впливає (тобто поширюється в глобальному масштабі ) на послідовність семантики вищого рівня. Наприклад, порядок оцінки (а також теоретично також дублювання) формул електронних таблиць не має значення, оскільки результати не копіюються на входи, поки не будуть обчислені всі виходи, тобто аналогічні чистим функціям.
C, Java, C ++, C #, PHP та JavaScript не є особливо декларативними. Синтаксис Copute і синтаксис Python більш декларативно поєднані з наміченими результатами , тобто послідовною синтаксичною семантикою, яка усуває сторонні, так що можна легко зрозуміти код після його забуття. Копут і Хаскелл застосовують детермінізм оперативної семантики і закликають " не повторювати себе " (DRY), оскільки вони дозволяють лише чисто функціональну парадигму.
2 Навіть там, де ми можемо довести семантику програми, наприклад, з мовою Coq, це обмежується семантикою, яка виражається під час набору тексту , і введення ніколи не може охопити всю семантику програми - навіть для мов, які є не Turing завершений, наприклад, за допомогою HTML + CSS можна висловити непослідовні комбінації, які, таким чином, мають не визначену семантику.
3 Багато пояснень помилково стверджують, що лише імперативне програмування має синтаксично впорядковані твердження. Я пояснив цю плутанину між імперативним та функціональним програмуванням . Наприклад, порядок висловлювань HTML не зменшує узгодженість їх значення.
Редагувати: Я опублікував такий коментар у блозі Роберта Харпера:
у функціональному програмуванні ... діапазон зміни змінної є типом
Залежно від того, як можна відрізнити функціональне від імперативного програмування, ваш "присвоєний" імперативній програмі також може мати тип, що обмежує його мінливість.
Єдине неясне визначення, яке я в даний час оцінюю для функціонального програмування, це: а) функції як першокласні об'єкти та типи; б) перевага для рекурсії через петлі та / або в) чисті функції - тобто ті функції, які не впливають на потрібну семантику програми при запам'ятовуванні ( таким чином, абсолютно чисто функціональне програмування не існує в денотаційній семантиці загального призначення через вплив оперативної семантики, наприклад, розподіл пам'яті ).
Властивість idempotent чистої функції означає, що виклик функції її змінних може бути замінено її значенням, що, як правило, не стосується аргументів імперативної процедури. Чисті функції, здається, є декларативними WT до неспоряджених переходів стану між типами вводу та результату.
Але склад чистих функцій не підтримує такої послідовності, тому що можна моделювати імперативний процес побічного (глобального стану) чистою функціональною мовою програмування, наприклад, IOMonad Haskell і, крім того, цілком неможливо запобігти виконанню таких в будь-яку повну чисту функціональну мову програмування.
Як я писав у 2012 році, що здається аналогічним консенсусом коментарів у вашому недавньому блозі , це декларативне програмування - це спроба зафіксувати уявлення про те, що передбачувана семантика ніколи не є непрозорою. Прикладами непрозорої семантики є залежність від порядку, залежність від стирання семантики вищого рівня на шарі оперативної семантики (наприклад, касти не є перетвореннями, а перероблені дженерики обмежують семантику вищого рівня ) та залежність від змінних значень, які неможливо перевірити (доведено правильно) мовою програмування.
Таким чином, я дійшов висновку, що декларативними можуть бути лише нетурїнські цілі мови.
Таким чином, одним з однозначних і чітких атрибутів декларативної мови може бути те, що її результати можуть бути доведені, щоб вони відповідали певній безлічі генеративних правил. Наприклад, для будь-якої конкретної програми HTML (ігнорування розбіжностей у способах розходження інтерпретаторів), що не є сценарієм (тобто не є Тюрінг завершеним), то його варіабельність виводу може бути безліч. Або, більш коротко, програма HTML - це чиста функція її змінності. Програма електронних таблиць - це чиста функція її вхідних змінних.
Тож мені здається, що декларативні мови є антитезою безмежної рекурсії , тобто за самореференційними теоремами про незавершеність Гереда не можна довести.
Лесі Лампорт написала казку про те, як Евклід міг би працювати над теоремами про незавершеність Геделя, застосованими до доказів математики в контексті мови програмування, завдяки конгруенції між типами та логікою (листування Кері-Говарда тощо).
Імперативне програмування: розповісти «машині», як щось робити, і в результаті відбудеться те, що ви хочете, щоб сталося.
Декларативне програмування: розповісти «машині», що ви хочете, щоб це сталося, і дати комп'ютеру зрозуміти, як це зробити.
function makeWidget(options) {
const element = document.createElement('div');
element.style.backgroundColor = options.bgColor;
element.style.width = options.width;
element.style.height = options.height;
element.textContent = options.txt;
return element;
}
function makeWidget(type, txt) {
return new Element(type, txt);
}
Примітка. Різниця не в стислість, складність чи абстракція. Як зазначено, різниця є тому, як проти чого .
В імперативі / декларативний / Функціональні аспекти були добре в минулому , щоб класифікувати загальні мови, але в даний час все «великому мовою» (як Java, Python, JavaScript і т.д.) мають деякий варіант ( як правило рамки ) , щоб висловити з «іншим фокусом» ніж його основний (звичайний імператив) і виражати паралельні процеси, декларативні функції, лямбда тощо.
Тож хорошим варіантом цього питання є "Який аспект добре класифікувати рамки сьогодні?" ... Важливим аспектом є те, що ми можемо позначити "стиль програмування" ...
Хороший приклад для пояснення. Як ви можете прочитати про jQuery у Вікіпедії ,
Набір основних функцій jQuery - вибір елементів DOM, обхід та маніпулювання - за допомогою його селекторного двигуна (...) створив новий "стиль програмування", сплавляючи алгоритми та DOM-структури даних.
Тож jQuery - найкращий (популярний) приклад зосередження на "новому стилі програмування" , який має не лише орієнтацію на об'єкт, а " алгоритми злиття та структури даних ". jQuery дещо реагує як електронні таблиці, але не "орієнтований на клітинку", це " орієнтований на вузол DOM " ... Порівнюючи основні стилі в цьому контексті:
Ніякого синтезу : у всіх "великих мовах", у будь-якому функціональному / декларативному / імперативному вираженні, звичайним є "відсутність злиття" даних та алгоритму, за винятком деякої орієнтації на об'єкти, тобто злиття з точки зору суворої структури алгебрики .
Деякий синтез : усі класичні стратегії злиття, в наш час мають деякі рамки, що використовують його як парадигму ... потік даних , програмування на основі подій (або старі мови, визначені для домену, як awk та XSLT ) ... Як програмування із сучасними електронними таблицями, вони також приклади стилю реактивного програмування .
Великий злиття : це "стиль jQuery" ... jQuery - це доменна мова, орієнтована на " алгоритми злиття та DOM-структури даних ".
PS: інші "мови запитів", як XQuery, SQL (з PL як опція імперативного вираження), також є прикладами злиття даних-алгоритму, але вони острови , без злиття з іншими системними модулями ... Весна , коли використовується find()
-варіанти та Специфікаційні пропозиції - ще один хороший приклад злиття.
Декларативне програмування - це програмування, виражаючи деяку позачасову логіку між входом і виходом, наприклад, у псевдокоді, наступний приклад був би декларативним:
def factorial(n):
if n < 2:
return 1
else:
return factorial(n-1)
output = factorial(argvec[0])
Ми просто визначимо тут відносини, які називаються "факторіальними", і визначили відносини між результатом і входом як ці відносини. Як повинно бути очевидно, що будь-яка структурована мова дозволяє декларативно програмувати в деякій мірі. Центральною ідеєю декларативного програмування є незмінні дані, якщо ви призначаєте змінну, ви робите це лише один раз, а потім ніколи більше. Інші, суворіші визначення, означають, що побічних ефектів взагалі не може бути, ці мови іноді називають "чисто декларативними".
Таким же результатом в імперативному стилі був би:
a = 1
b = argvec[0]
while(b < 2):
a * b--
output = a
У цьому прикладі ми не виражали вічну статичну логічну залежність між входом і виходом, ми змінювали адреси пам'яті вручну, поки одна з них не забезпечила бажаний результат. Повинно бути очевидним, що всі мови дозволяють декларативну семантику до деякого розширення, але не всі дозволяють імперативу, деякі "чисто" декларативні мови дозволяють побічні ефекти і мутацію взагалі.
Декларативні мови часто кажуть, що вказують на те, що потрібно зробити, на відміну від "як це зробити", я думаю, що це неправильно, декларативні програми все ще вказують, як треба діставатись від введення до виводу, але іншим способом - відносини, які ви вказуєте, повинні бути ефективно обчислювані (важливий термін, шукайте його, якщо ви цього не знаєте). Інший підхід - недетермінований програмування, яке дійсно просто вказує, яким умовам результат значно відповідає, перш ніж ваша реалізація просто вичерпає всі шляхи проб і помилок, поки це не вдасться.
Чисто декларативні мови включають Haskell і Pure Prolog. Шкала ковзання від одного і до іншого буде: Pure Prolog, Haskell, OCaml, Scheme / Lisp, Python, Javascript, C--, Perl, PHP, C ++, Pascall, C, Fortran, Assembly
factorial
не мутує жодного значення.
Тут є кілька хороших відповідей щодо зазначених "типів".
Я подаю кілька додаткових, "екзотичніших" концепцій, часто пов'язаних з набором функціональних програм:
Я думаю, що ваша таксономія неправильна. Існує два протилежні типи імперативу та декларативу. Функціонал - це лише підтип декларативного. До речі, wikipedia стверджує той самий факт.
Коротше кажучи, чим більше стиль програмування підкреслює, що (робити), абстрагуючи деталі як (робити це), тим більше цей стиль вважається декларативним. Навпаки стосується імперативу. Функціональне програмування пов'язане з декларативним стилем.