Функціональне, декларативне та імперативне програмування [закрито]


466

Що означають терміни функціональне, декларативне та імперативне програмування?


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

1
@Kit Imo, деякі відповіді на цій сторінці суперечать умовам. DP == референтна прозорість (RT). DP & IP - це протилежності, тому afaics не є доповненням цілого, тобто вся програма може бути написана в будь-якому стилі. Виклик функції може бути або DP (RT), або IP, його реалізація може бути або мікс. Вони не є симбіотичними в тому сенсі, що виклик функції IP в іншому випадку функція DP може зробити IP-дзвінок функції DP. Вони симбіотичні в тому сенсі, що реальні програми (наприклад, функціональні реактивні) програми можуть використовувати суміш, наприклад IP-дзвінки верхнього рівня в функції DP.
Шелбі Мур III

ahould бути додані в вікі або посилання на що - щось схоже на вікі і т.д. тут відмінна посилання на Вікіпедію en.wikipedia.org/wiki/Comparison_of_programming_paradigms
Joe


1
Це питання обговорюється на Meta: meta.stackoverflow.com/q/342784/2751851
дуплод

Відповіді:


262

На момент написання цього запису голосні відповіді на цій сторінці є неточними та заплутаними щодо декларативного проти імперативного визначення, включаючи відповідь, що цитує Вікіпедію. Деякі відповіді співпадають з термінами по-різному.

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

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

Визначення декларативного вираження

Тільки атрибут , який може можливо диференціювати декларативне вираження з імперативного вираження є посилальної прозорістю (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 КБН із охочею копродукцією.


Навіть при декларативному програмуванні обмежень обмеження не змінюються, поки вирішувач знаходить рішення. Це очевидно, тому що немає способу вказати час для їх зміни. Навіть обмеження, вказані wrt, інші обмеження всі заявляються до запуску рішення для пошуку рішення. Це аналогічно декларативним формулам у таблиці .
Шелбі Мур III

3
Скорочення не означає дати визначення. Там, де я писав, "RT часто скорочується" немає побічних ефектів ", це не означає, що визначення RT є" немає побічних ефектів ", оскільки люди можуть мати різні визначення для" ефектів ". Якщо я замість цього сказав "RT часто скорочується" xyz "", безглуздий символ не дає ніякого визначення RT. RT має чітке визначення, яке ніколи не змінюється, незалежно від того, який символ використовується для позначення.
Шелбі Мур III

Я не можу знайти протилежний приклад моєму твердженню, що всі види ДП - це RT. Наприклад, значення (тобто значення) термінів контекстно-чутливої ​​граматики не змінюється в інший час або положення в граматиці. Дивіться мій коментар із програмування обмежень вище.
Шелбі Мур III

1
Порівнюючи C у стилі ESP з RT у монаді держави, недійсне , оскільки кожне твердження C може мутувати глобальний стан, тоді як "всередині" стан монади кожне відповідне твердження генерує КОПІЮЦІЮ стану (настільки модифікованого). Останнє - RT - колишнє - ні. Монадійний склад завжди є RT. DP == RT - це єдине значення для DP, яке є непересічним набором атрибутів (математичний доказ я правильний, інакше DP безглуздо).
Шелбі Мур III

1
Я б хотів, щоб я міг зрозуміти це минуле перше речення. Я читав посібник для DAX, який вказував, що це "функціональна мова". Що це означає? Я не знаю, іди запитайте свого попса
Nick.McDermaid

103

Не існує насправді жодного неоднозначного об’єктивного визначення для них. Ось як я їх би визначив:

Імператив - Основна увага на те , що кроки , які комп'ютер повинен прийняти , а не те , що комп'ютер буде робити (колишній C, C ++, Java.).

Декларативний. Основна увага приділяється тому, що повинен робити комп'ютер, а не тому, як це робити (наприклад, SQL).

Функціональний - підмножина декларативних мов, що має велику увагу на рекурсії


1
Майте на увазі пару речей: 1) пояснення призначене для простого, а не всеосяжного 2) як я вже сказав, існує кілька способів визначення цих мов. Таким чином, відповідь цілком може бути помилковим для вас і правильним для когось іншого.
Джейсон Бейкер

3
Функціональне програмування не є "підмножиною декларативних мов". Декларативне програмування вимагає незмінності збережених значень, функціональне програмування не робить, якщо це не чисто FP. Дивіться мою відповідь . Дивіться також пояснення для комірок електронної таблиці . Правильні об'єктивні визначення не є "неоднозначними". Імперативне програмування також орієнтоване "на те, що повинен робити комп'ютер". Тільки відмінність імперативне програмування має справу із змінними збереженими значеннями.
Шелбі Мур III

5
@ShelbyMooreIII - Я схильний погоджуватися з Еріком Мейєром щодо цього. Не існує насправді такого поняття, як "нечиста функціональна мова". Що стосується мене, Ocaml, F # тощо є обов'язковими мовами з функціональною структурою даних. Але, як я вже говорив у своїй відповіді, я не вважаю, що існує жодна об'єктивна, неоднозначна відповідь на це питання. Існує кілька способів визначення речей.
Джейсон Бейкер

3
Математично можна довести, що він плутає терміни, коли жодне з визначень не є однозначним, оскільки обрані атрибути не є суперечливим набором. Якщо ви визначаєте FP лише як чистий FP (тобто RT), він не відрізняється від DP, пор. моя відповідь . До розрізнених атрибутів FP входить тип першого класу, який може бути імперативною функцією. Більш фундаментальні терміни я знайшов тут і тут . Перевага чистого FP є ортогональним для визначення просто FP.
Шелбі Мур III

21
@ShelbyMooreIII - Я робив припущення, що ОП хоче його відповіді англійською мовою, а не Math Nerd-ese. Якщо це було неправдивим припущенням, то мої вибачення.
Джейсон Бейкер

54

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

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

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

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

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

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

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

підсумовуючи, тоді:

  • імперативний та декларативний - це два протилежних стилі програмування (однакові назви використовуються для мов програмування, які заохочують ці стилі)

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

тому "функціональне програмування" часто описується як "декларативне".


5
Найкраще пояснення поки що. Здається, функціональні та ООП є ортогональними імперативними та деклараційними.
Дідьє А.

Ви б сказали, що логічне програмування є декларативним? Або вона сама ортогональна?
Дідьє А.

51

Коротко:

Імперативний мову specfies ряд інструкцій , які комп'ютер виконує в послідовності (зробити це, то зробити це).

Декларативний мову оголошує набір правил про те, що результати повинні бути результатом яких входів (наприклад, якщо у вас є, то результат B). Двигун застосує ці правила до входів і дасть вихід.

Функціональний мова оголошує набір математичних / логічних функцій , які визначають , як вхід переводяться на вихід. напр. f (y) = y * y. це тип декларативної мови.


1
Функціональне програмування не є "типом декларативної мови". Декларативне програмування вимагає незмінності збережених значень, нечисте функціональне програмування не робить. Дивіться мою відповідь . Дивіться також пояснення для комірок електронної таблиці . Тільки причина , обов'язково логіка (він же інструкції) виконуються в послідовності є те , що з - за наявності змінюваних збережених значень, результат залежить від порядку оцінки. Використовуючи свій словниковий запас, "інструкція" може (і "правило" не може) працювати на змінних значеннях.
Шелбі Мур III

23

Імператив: як досягти нашої мети

   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

Ви описуєте функціональне програмування проти не FP, а не декларативне проти імперативного програмування. Функціональне програмування є ортогональним полярності між імперативним та декларативним програмуванням. Декларативне програмування вимагає незмінності збережених значень, нечисте функціональне програмування не робить. Дивіться мою відповідь .
Шелбі Мур III

22

Імперативне програмування означає будь-який стиль програмування, де ваша програма побудована з інструкцій, що описують, як будуть відбуватися операції, виконані комп'ютером .

Декларативне програмування означає будь-який стиль програмування, де ваша програма описує проблему чи рішення, але не чітко вказує, як буде виконуватися робота .

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

Логічне програмування (наприклад, у Prolog) - це ще одна форма декларативного програмування. Він включає обчислення, вирішуючи, чи є логічне твердження істинним (чи можна його задовольнити). Програма, як правило, являє собою низку фактів і правил - тобто опис, а не серія інструкцій.

Переписування термінів (наприклад, CASL) - це ще одна форма декларативного програмування. Він передбачає символічну трансформацію алгебраїчних термінів. Це повністю відрізняється від логічного програмування та функціонального програмування.


Функціональне програмування не є "формою декларативного програмування". Декларативне програмування вимагає незмінності збережених значень, нечисте функціональне програмування не робить. Дивіться мою відповідь . Дивіться також пояснення для комірок електронної таблиці . Термін "робота" в "описувати, як зробити роботу" не визначений. Тільки причина , важливо , логіка ( так звані «інструкції») виконуються в послідовності є те , що з - за наявності змінюваних збережених значень, результат залежить від порядку оцінки.
Шелбі Мур III

2
Будь ласка, сприймайте це як читайте, що я говорив про чисте функціональне програмування . Ці парадигми можуть перетинатися, і я не хочу забиватися, порівнюючи гібридні мови. Теоретично принаймні функціональне програмування стосується функцій, а не опису, як комп'ютер буде виконувати кожен обчислення - тому я вважаю, що це декларативне.
Дафідд Різ

Я відредагував свою відповідь , і в розділі "Функціональне програмування" я додав сценарій, де ми могли б стверджувати, що ПП завжди чистий, а нечистий FP - це справді "процедурне програмування". Вибачення за те, що раніше не було включено цю інтерпретацію.
Шелбі Мур III

13

імператив - вирази описують послідовність дій, які потрібно виконати (асоціативні)

декларативний - вирази - це декларації, що сприяють поведінці програми (асоціативна, комутативна, ідентифікаційна, монотонна)

функціональний - вирази мають значення як єдиний ефект; семантика підтримує еквівалентне міркування


1
Декларативні вирази сприяють передбачуваній поведінці програми, імперативні можуть сприяти передбачуваному чи ненавмисному. Декларативне значення не повинно бути комутативним та безвідмовним, якщо це навмисна семантика. Мені подобається ваша стисла суть функціоналу, тому я її схвалив.
Шелбі Мур III,

10

Оскільки я написав попередню відповідь, я сформулював нове визначення декларативного властивості, яке цитується нижче. Я також визначив імперативне програмування як подвійне властивість.

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

Цитуване пояснення визначення обговорює роль чисто функціонального програмування в декларативному програмуванні.

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

Декларативний проти імперативного

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

Занадто спрощене, технічно неточне і часто неоднозначне декларативне визначення як « що робити », а імператив як « як робити » . Неоднозначний випадок - " що " - це " як" " у програмі, яка виводить програму - компіляторі.

Очевидно, що необмежена рекурсія, яка робить мову Тьюрінга завершеною , є аналогічно і в семантиці - не тільки в синтаксичній структурі оцінки (він же оперативної семантики). Це логічно приклад, аналогічний теоремі Геделя - " будь-яка повна система аксіом також невідповідна ". Поміркуйте над суперечливою дивністю цієї цитати! Це також приклад, який демонструє, як вираз семантики не має доказуваної межі, тому ми не можемо довести 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 - це чиста функція її змінності. Програма електронних таблиць - це чиста функція її вхідних змінних.

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

Лесі Лампорт написала казку про те, як Евклід міг би працювати над теоремами про незавершеність Геделя, застосованими до доказів математики в контексті мови програмування, завдяки конгруенції між типами та логікою (листування Кері-Говарда тощо).


Здається, Роберт Харпер погоджується зі мною щодо безглуздості більшості декларативних дефініцій , але я не думаю, що він бачив моє вище. Він дійсно наближається до мого визначення, де він обговорює денотаційну семантику, але він не доходить до мого визначення. Модель (Денотаціонная семантика) вище рівня .
Шелбі Мур III

7

Імперативне програмування: розповісти «машині», як щось робити, і в результаті відбудеться те, що ви хочете, щоб сталося.

Декларативне програмування: розповісти «машині», що ви хочете, щоб це сталося, і дати комп'ютеру зрозуміти, як це зробити.

Приклад імперативу

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);
}

Примітка. Різниця не в стислість, складність чи абстракція. Як зазначено, різниця є тому, як проти чого .


2
хороший, але краще, якщо ви подасте принаймні один приклад для обох!
Pardeep Jain

4

Сьогодні новий фокус: нам потрібні старі класифікації?

В імперативі / декларативний / Функціональні аспекти були добре в минулому , щоб класифікувати загальні мови, але в даний час все «великому мовою» (як Java, Python, JavaScript і т.д.) мають деякий варіант ( як правило рамки ) , щоб висловити з «іншим фокусом» ніж його основний (звичайний імператив) і виражати паралельні процеси, декларативні функції, лямбда тощо.

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

Зосередьтеся на злитті даних з алгоритмом

Хороший приклад для пояснення. Як ви можете прочитати про jQuery у Вікіпедії ,

Набір основних функцій jQuery - вибір елементів DOM, обхід та маніпулювання - за допомогою його селекторного двигуна (...) створив новий "стиль програмування", сплавляючи алгоритми та DOM-структури даних.

Тож jQuery - найкращий (популярний) приклад зосередження на "новому стилі програмування" , який має не лише орієнтацію на об'єкт, а " алгоритми злиття та структури даних ". jQuery дещо реагує як електронні таблиці, але не "орієнтований на клітинку", це " орієнтований на вузол DOM " ... Порівнюючи основні стилі в цьому контексті:

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

  2. Деякий синтез : усі класичні стратегії злиття, в наш час мають деякі рамки, що використовують його як парадигму ... потік даних , програмування на основі подій (або старі мови, визначені для домену, як awk та XSLT ) ... Як програмування із сучасними електронними таблицями, вони також приклади стилю реактивного програмування .

  3. Великий злиття : це "стиль jQuery" ... jQuery - це доменна мова, орієнтована на " алгоритми злиття та DOM-структури даних ".
    PS: інші "мови запитів", як XQuery, SQL (з PL як опція імперативного вираження), також є прикладами злиття даних-алгоритму, але вони острови , без злиття з іншими системними модулями ... Весна , коли використовується find()-варіанти та Специфікаційні пропозиції - ще один хороший приклад злиття.


3

Декларативне програмування - це програмування, виражаючи деяку позачасову логіку між входом і виходом, наприклад, у псевдокоді, наступний приклад був би декларативним:

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не мутує жодного значення.
Шелбі Мур III

3

Тут є кілька хороших відповідей щодо зазначених "типів".

Я подаю кілька додаткових, "екзотичніших" концепцій, часто пов'язаних з набором функціональних програм:

  • Мова домену або DSL програмування : створення нової мови для вирішення проблеми.
  • Метапрограмування : коли ваша програма пише інші програми.
  • Еволюційне програмування : де ви будуєте систему, яка постійно вдосконалює себе або генерує послідовно кращі покоління підпрограм.

3

Я думаю, що ваша таксономія неправильна. Існує два протилежні типи імперативу та декларативу. Функціонал - це лише підтип декларативного. До речі, wikipedia стверджує той самий факт.


+1: Так, парадигми - це яблука та апельсини.
Nikhil Chelliah

ПП - це не просто підтип декларативного характеру. FP ортогональна полярності імперативу проти DP. DP вимагає незмінності збережених значень, нечистий FP не робить. Вікіпедія поєднує чисту FP з FP, з абсурдним твердженням, що такі поняття "взагалі чужі імперативному програмуванню": першокласні функції, рекурсія, порядок оцінювання та статичне введення тексту. Тоді Вікіпедія допускає нечисте "Функціональне програмування нефункціональними мовами".
Шелбі Мур III

У цьому питанні Вікіпедія помилкова. Багато популярних функціональних мов дозволяють програмувати в "декларативному стилі", якщо ви не хочете, але це не декларативні мови. Але те ж саме можна сказати і про C, де ви все одно можете програмувати у функціональному стилі, якщо захочете, використовуючи void * s.
Plynx

Напевно, я мав би бути більш чітким у цьому питанні, але з іншого боку, я б не збирався зіпсувати стартову тему з не зовсім релевантними (іммо) деталями. Я бачу, що функціональні мови, як правило, використовуються декларативно. Ви можете спробувати написати декларативно та / або функціонально в ASM або C, або, можливо, ви можете написати імперативну програму в Lisp, але я сумніваюся, що це було б дуже корисно або інформативно для автора питання. Тож по суті я все-таки вважаю свою відповідь доречною, навіть якщо вона могла бути по-іншому сформульована.
Рорік

2

Коротше кажучи, чим більше стиль програмування підкреслює, що (робити), абстрагуючи деталі як (робити це), тим більше цей стиль вважається декларативним. Навпаки стосується імперативу. Функціональне програмування пов'язане з декларативним стилем.


Дивіться мої коментарі нижче інших відповідей. ПП не завжди є декларативним. Що проти того, як неправильна систематика для IP проти DP, оскільки і DP, і IP мають логіку, яка передбачає, що і як.
Шелбі Мур III
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.