Co to jest programowanie deklaratywne? [Zamknięte]

193

Ciągle słyszę ten termin w różnych kontekstach. Co to jest?

Brian G.
źródło
7
Odpowiedź wybrana jako prawidłowa (oznaczona zielonym znakiem zaznaczenia) jest nieprawidłowa. Nie definiuje, co odróżnia programowanie deklaratywne od jego antytezy - programowanie imperatywne. Proszę rozważyć zmianę wyboru.
Shelby Moore III,
3
Tak, odpowiedź oznaczona jako poprawna NIE jest poprawna.
Dermot
4
@ShelbyMooreIII Określ również, która odpowiedź jest poprawna, abyśmy mogli ją przeczytać!
vivek.m
@ vivek.m Dzisiaj podałem nową odpowiedź .
Shelby Moore III,

Odpowiedzi:

148

Programowanie deklaratywne polega na pisaniu kodu w sposób opisujący to, co chcesz zrobić, a nie sposób, w jaki chcesz to zrobić. Kompilator musi ustalić, jak to zrobić.

Przykładami deklaratywnych języków programowania są SQL i Prolog.

1800 INFORMACJI
źródło
29
Nadal musisz dowiedzieć się, jak powiedzieć komputerowi, czego chcesz :)
hasen
7
@hasenj to i inne odpowiedzi nie definiują jedynego atrybutu niepodzielonego z programowaniem imperatywnym - czyli niezmienności .
Shelby Moore III,
3
Będzie naprawdę świetnie, jeśli możesz wspomnieć o tym, czym różni się od programowania imperatywnego (języki takie jak C, C ++, C #), wtedy czytelnikom łatwiej będzie dostrzec różnicę.
RBT
1
programista : „Chcę pojechać do Paryża”. declarative (c) : „Jak chciałbyś się tam dostać? płynąć łodzią? lub latać samolotem? może popłynąć w połowie drogi, a następnie przelecieć resztę drogi tam?” programista : „Nie interesuje mnie, jak to się robi”. imperative (sql) : „Nie martw się. Mogę zapytać o to, czego potrzebujesz”. ( tak rozumiem odpowiedź )
data
Jak SQL może być deklaratywny, jeśli obsługuje wyrażenia, które nie są transparentnie referencyjne?
java-addict301
80

Inne odpowiedzi już fantastycznie wyjaśniają, czym jest programowanie deklaratywne, dlatego przedstawię kilka przykładów, dlaczego może to być przydatne.

Kontekst Niezależność

Programy deklaratywne są niezależne od kontekstu . Ponieważ deklarują jedynie ostateczny cel, ale nie pośrednie kroki do osiągnięcia tego celu, ten sam program może być wykorzystywany w różnych kontekstach. Jest to trudne w przypadku programów imperatywnych , ponieważ często zależą one od kontekstu (np. Stan ukryty).

Weź yaccjako przykład. Jest to także generator parserów. kompilator kompilator, zewnętrzna deklaratywna DSL do opisywania gramatyki języka, dzięki czemu parser dla tego języka może być automatycznie generowany z opisu. Ze względu na niezależność od kontekstu, przy pomocy takiej gramatyki możesz robić wiele różnych rzeczy:

  • Wygeneruj parser C dla tej gramatyki (oryginalny przypadek użycia dla yacc)
  • Wygeneruj parser C ++ dla tej gramatyki
  • Wygeneruj parser Java dla tej gramatyki (używając Jaya)
  • Wygeneruj parser C # dla tej gramatyki (używając GPPG)
  • Wygeneruj parser Ruby dla tej gramatyki (używając Racc)
  • Wygeneruj wizualizację drzewa dla tej gramatyki (używając GraphViz)
  • po prostu wykonaj ładne drukowanie, fantazyjne formatowanie i podświetlanie składni samego pliku źródłowego yacc i dołącz go do Podręcznika jako składniowej specyfikacji twojego języka

I wiele więcej …

Optymalizacja

Ponieważ nie określasz komputera, jakie kroki należy podjąć i w jakiej kolejności, może on znacznie swobodniej zmieniać układ programu, a nawet wykonywać niektóre zadania równolegle. Dobrym przykładem jest planer zapytań i optymalizator zapytań do bazy danych SQL. Większość baz danych SQL pozwala wyświetlić zapytanie, które faktycznie wykonują, w porównaniu z zapytaniem, o które je poprosiłeś . Często te zapytania nic nie wyglądająlubią się nawzajem. Planer zapytań bierze pod uwagę rzeczy, o których nawet byś nie marzył: na przykład opóźnienie obrotu talerza dysku lub fakt, że jakaś inna aplikacja dla zupełnie innego użytkownika właśnie wykonała podobne zapytanie i tabelę, którą jesteś dołączanie się i że tak ciężko pracowałeś, aby uniknąć ładowania, i tak jest już w pamięci.

Jest to ciekawy kompromis tutaj: maszyna musi pracować ciężej, aby dowiedzieć się, jak coś zrobić, niż miałoby to miejsce w języku bezwzględnej, ale kiedy to robi zrozumieć to, że ma znacznie większą swobodę i wiele więcej informacji na optymalizację etap.

Jörg W Mittag
źródło
23

Luźno:

Programowanie deklaratywne dąży do:

  • Zestawy deklaracji lub deklaratywnych instrukcji, z których każda ma znaczenie (często w dziedzinie problemowej) i może być rozumiana niezależnie i oddzielnie.

Programowanie imperatywne dąży do:

  • Sekwencje poleceń, z których każde wykonuje pewną akcję; ale które mogą, ale nie muszą mieć znaczenia w dziedzinie problemów.

W rezultacie styl imperatywny pomaga czytelnikowi zrozumieć mechanikę tego, co faktycznie robi system, ale może dać niewielki wgląd w problem, który ma rozwiązać. Z drugiej strony deklaratywny styl pomaga czytelnikowi zrozumieć dziedzinę problemu i podejście, jakie system przyjmuje do rozwiązania problemu, ale jest mniej pouczający w kwestii mechaniki.

Prawdziwe programy (nawet te napisane w językach, które faworyzują końce spektrum, takie jak ProLog lub C) zazwyczaj mają oba style obecne w różnym stopniu w różnych punktach, aby zaspokoić różne złożoności i potrzeby komunikacyjne utworu. Jeden styl nie jest lepszy od drugiego; służą po prostu innym celom i, podobnie jak w przypadku wielu rzeczy w życiu, umiar jest kluczowy.

William Payne
źródło
To poprawna odpowiedź. Żadnego z tych bełkotów powyżej
Krzysztof Wende
Dziękuję, że nie tylko odpowiedziałeś na pytanie, ale zrobiłeś to w stylu „Wyjaśnij, jak jestem 5” z kontekstem i praktycznością. Doskonała odpowiedź.
monsto
17

Oto przykład.

W CSS (używanym do stylizowania stron HTML), jeśli chcesz, aby element obrazu miał 100 pikseli wysokości i 100 pikseli szerokości, po prostu „oświadczasz”, że to, co chcesz, w następujący sposób:

#myImageId {
height: 100px;
width: 100px;
}

Możesz uznać CSS za deklaratywny język „arkusza stylów”.

Silnik przeglądarki, który czyta i interpretuje ten CSS, może sprawić, że obraz będzie wyglądał tak wysoko i tak szeroko, jak chce. Różne silniki przeglądarki (np. Silnik IE, silnik Chrome) będą realizować to zadanie inaczej.

Ich unikalne implementacje NIE są oczywiście napisane w języku deklaratywnym, ale w proceduralnym, takim jak Assembly, C, C ++, Java, JavaScript lub Python. Ten kod to kilka kroków, które należy wykonać krok po kroku (i mogą obejmować wywołania funkcji). Może to robić interpolować wartości pikseli i renderować na ekranie.

Niko Bellic
źródło
11

Przykro mi, ale muszę się nie zgodzić z wieloma innymi odpowiedziami. Chciałbym zatrzymać to mętne niezrozumienie definicji programowania deklaratywnego.

Definicja

Przezroczystość referencyjna (RT) wyrażeń podrzędnych jest jedynym wymaganym atrybutem deklaratywnego wyrażenia programistycznego , ponieważ jest to jedyny atrybut, który nie jest współdzielony z programowaniem imperatywnym.

Inne cytowane atrybuty programowania deklaratywnego pochodzą z tej RT. Kliknij powyższy link, aby uzyskać szczegółowe wyjaśnienie.

Przykład arkusza kalkulacyjnego

Dwie odpowiedzi wspomniały o programowaniu arkuszy kalkulacyjnych. W przypadkach, gdy programowanie arkusza kalkulacyjnego (inaczej formuł) nie ma dostępu do zmiennego stanu globalnego , jest to programowanie deklaratywne. To dlatego, że komórki Zmienne wartości są monolityczne wejście i wyjście z main()(cały program). Nowe wartości nie są zapisywane w komórkach po wykonaniu każdej formuły, dlatego nie można ich modyfikować przez cały czas życia programu deklaratywnego (wykonanie wszystkich formuł w arkuszu kalkulacyjnym). W związku z tym formuły postrzegają te zmienne komórki jako niezmienne. Funkcja RT ma dostęp do niezmiennego stanu globalnego (a także zmiennego stanu lokalnego ).

Zatem zdolność do mutowania wartości w komórkach, gdy program kończy się (jako wyjście main()), nie powoduje, że można je modyfikować przechowywane wartości w kontekście reguł. Kluczowym rozróżnieniem jest to, że wartości komórek nie są aktualizowane po wykonaniu każdej formuły arkusza kalkulacyjnego, dlatego kolejność wykonywania formuł nie ma znaczenia. Wartości komórek są aktualizowane po wykonaniu wszystkich formuł deklaratywnych.

Shelby Moore III
źródło
1
Niezamierzone skutki uboczne mogą zniszczyć związek między tym, co zadeklarowano, a faktycznym zachowaniem programu. Wyjaśniłem to bardziej szczegółowo w nowej odpowiedzi .
Shelby Moore III
8

Programowanie deklaratywne to obraz, przy czym programowanie imperatywne to instrukcje do malowania tego obrazu.

Pisząc w sposób deklaratywny, piszesz „Mówisz, co to jest”, zamiast opisywać kroki, jakie powinien podjąć komputer, aby dostać się tam, gdzie chcesz.

Kiedy używasz XML do oznaczania danych, używasz deklaratywnego programowania, ponieważ mówisz: „To jest osoba, która ma urodziny, a tam jest adres”.

Kilka przykładów połączenia programowania deklaratywnego i imperatywnego w celu uzyskania większego efektu:

  • Windows Presentation Foundation używa deklaratywnej składni XML do opisania wyglądu interfejsu użytkownika oraz relacji (powiązań) między kontrolkami i bazowymi strukturami danych.

  • Strukturalne pliki konfiguracyjne używają deklaratywnej składni (tak proste, jak pary „klucz = wartość”), aby zidentyfikować, co oznacza ciąg lub wartość danych.

  • HTML zaznacza tekst znacznikami, które opisują rolę każdego fragmentu tekstu w stosunku do całego dokumentu.

Chris Wenham
źródło
2
Chociaż XML jest deklaratywny, nie posunąłbym się do stwierdzenia, że ​​jest to programowanie deklaratywne po prostu dlatego, że nie ma aktywnej semantyki związanej ze znacznikami. Powiedzenie, że coś jest adresem, nie pomaga w ustaleniu, co chcesz z tym zrobić.
HenryR
1
Musi istnieć kontekst (domena?), W którym używany jest program deklaratywny. Tak więc używanie XML w połączeniu z ANT może być interpretowane jako program deklaratywny.
Gutzofter,
7

Programowanie deklaratywne to programowanie z deklaracjami, tzn. Zdaniami deklaratywnymi. Zdania deklaratywne mają szereg właściwości, które odróżniają je od zdań rozkazujących. W szczególności deklaracjami są:

  • przemienny (można zmienić kolejność)
  • asocjacyjny (można przegrupować)
  • idempotent (można powtarzać bez zmiany znaczenia)
  • monotoniczny (deklaracje nie odejmują informacji)

Istotną kwestią jest to, że są to wszystkie właściwości strukturalne i są prostopadłe do przedmiotu. W deklaratywnym nie chodzi o „Co vs. Jak” . Możemy zadeklarować (reprezentować i ograniczyć) „jak” równie łatwo, jak deklarujemy „co” . Deklaratywna jest struktura, a nie treść. Programowanie deklaratywne ma znaczący wpływ na to, w jaki sposób wyodrębniamy i refaktoryzujemy nasz kod oraz jak modulujemy go do podprogramów, ale nie tak bardzo w modelu domeny.

Często możemy zmienić z trybu rozkazującego na tryb deklaratywny, dodając kontekst. Np. „Skręć w lewo. (... poczekaj na to ...) Skręć w prawo.” na „Bob skręci w lewo na skrzyżowaniu Foo i Bar o 11:01. Bob skręci w prawo na skrzyżowaniu Bar i Baz o 11:06”. Zauważ, że w tym drugim przypadku zdania są idempotentne i przemienne, podczas gdy w pierwszym przypadku zmiana lub powtórzenie zdań poważnie zmieniłoby znaczenie programu.

Jeśli chodzi o monotonię , deklaracje mogą dodawać ograniczenia, które odejmują możliwości . Ale ograniczenia wciąż dodają informacje (a dokładniej, ograniczenia są informacją). Jeśli potrzebujemy deklaracji zmieniających się w czasie, typowe jest modelowanie tego z wyraźną semantyką czasową - np. Od „kula jest płaska” do „kula jest płaska w czasie T”. Jeśli mamy dwie sprzeczne deklaracje, mamy niespójny system deklaratywny, chociaż można to rozwiązać poprzez wprowadzenie miękkich ograniczeń (priorytetów, prawdopodobieństw itp.) Lub wykorzystanie logiki parakonsekwentnej.

dmbarbour
źródło
1
Wyrażenia deklaratywne przyczyniają się do zamierzonego zachowania programu, tryb rozkazujący może przyczyniać się do zamierzonego lub niezamierzonego. Deklaratywna nie musi być przemienna i idempotentna, jeśli jest to celowa semantyka.
Shelby Moore III
6

Opisywanie komputerowi tego, czego chcesz, a nie jak coś zrobić.

denonde
źródło
6

wyobraź sobie stronę programu Excel. Z kolumnami wypełnionymi formułami do obliczenia zwrotu podatku.

Cała logika jest zadeklarowana w komórkach, kolejność obliczeń jest ustalana na podstawie samej formuły, a nie proceduralnie.

Na tym właśnie polega programowanie deklaratywne. Zadeklarujesz przestrzeń problemu i rozwiązanie, a nie przebieg programu.

Prolog jest jedynym deklaratywnym językiem, którego używam. Wymaga to innego sposobu myślenia, ale dobrze jest nauczyć się, jeśli tylko narażasz się na coś innego niż typowy język programowania proceduralnego.

paan
źródło
6

Dopracowałem swoje rozumienie programowania deklaratywnego od grudnia 2011 r., Kiedy udzieliłem odpowiedzi na to pytanie. Oto moje obecne zrozumienie.

Długa wersja mojego zrozumienia (badania) została szczegółowo opisana pod tym linkiem , który należy przeczytać, aby uzyskać głębokie zrozumienie podsumowania, które przedstawię poniżej.

Programowanie imperatywne polega na zapisywaniu i odczytywaniu stanu zmiennego, a zatem kolejność i / lub powielanie instrukcji programu może zmienić zachowanie programu (semantykę) (a nawet spowodować błąd, tj. Niezamierzone zachowanie).

W najbardziej naiwnym i ekstremalnym sensie (który twierdziłem w mojej poprzedniej odpowiedzi) programowanie deklaratywne (DP) unika całego przechowywanego stanu zmiennego, dlatego uporządkowanie i / lub powielanie instrukcji programu NIE może zmienić zachowania (semantyki) programu .

Jednak taka ekstremalna definicja nie byłaby bardzo przydatna w prawdziwym świecie, ponieważ prawie każdy program wymaga zmagazynowanego stanu. Na przykład arkusz kalkulacyjny zgodny z tą definicją ekstremalnych DP, ponieważ cały kod programu jest prowadzony do końca z jednego statycznego kopii stanu wejścia, zanim zostaną zapisane nowe kraje. Następnie, jeśli jakikolwiek stan zostanie zmieniony, jest to powtarzane. Ale większość programów w świecie rzeczywistym nie może być ograniczona do takiego monolitycznego modelu zmian stanu.

Bardziej użyteczną definicją DP jest to, że kolejność i / lub powielanie instrukcji programowania nie zmienia żadnej nieprzejrzystej semantyki. Innymi słowy, nie występują ukryte losowe zmiany semantyki - wszelkie zmiany w kolejności instrukcji programu i / lub duplikacji powodują jedynie zamierzone i przejrzyste zmiany w zachowaniu programu.

Następnym krokiem byłoby omówienie, które modele programowania lub paradygmaty pomagają w DP, ale nie o to tutaj chodzi.

Shelby Moore III
źródło
Aktualizacja: proszę odnieść się również do bardziej wyczerpującego wyjaśnienia w mojej innej odpowiedzi dotyczącej definicji programowania deklaratywnego.
Shelby Moore III,
Functional programmingjest obecnie modnym słowem, które jest zasadniczo podzbiorem deklaratywnego programowania. LINQ w języku C # jest elementem programowania funkcjonalnego, gdy sam język jest z natury konieczny. Tak więc C # staje się rodzajem hybrydy opartej na tej definicji.
RBT
1
Link do compute.com nie działa.
Kedar Mhaswade
5

Jest to metoda programowania oparta na opisie tego, co należy zrobić lub być, a nie na tym , jak to powinno działać.

Innymi słowy, nie piszesz algorytmów wykonanych z wyrażeń, po prostu układasz, jak chcesz, aby rzeczy były. Dwa dobre przykłady to HTML i WPF.

Ten artykuł w Wikipedii stanowi dobry przegląd: http://en.wikipedia.org/wiki/Declarative_programming

Kevin Berridge
źródło
1
Drobne spory. WPF to biblioteka, a nie język ani paradygmat. Myślę, że naprawdę chciałeś powiedzieć, że XAML jest przykładem języka deklaratywnego.
Nick
A jak opisałbyś programowanie przy użyciu biblioteki / frameworka?
Gutzofter,
Niepoprawne jest stwierdzenie, że programowanie deklaratywne nie może zawierać wyrażeń. Kluczowym rozróżnieniem jest to, że wyrażenia nie mogą mutować przechowywanych wartości .
Shelby Moore III,
HTML nie jest językiem programowania
lud
5

Ponieważ napisałem moją wcześniejszą odpowiedź, sformułowałem nową definicję właściwości deklaratywnej, która jest cytowana poniżej. Zdefiniowałem także programowanie imperatywne jako podwójną właściwość.

Ta definicja jest lepsza od tej, którą podałem w poprzedniej odpowiedzi, ponieważ jest zwięzła i bardziej ogólna. Ale może być trudniej zrozumieć, ponieważ implikacje twierdzeń o niekompletności mających zastosowanie do programowania i życia w ogólności są trudne dla ludzi, aby otoczyli umysł.

Cytowany wyjaśnienie definicji omawia rolę czysto funkcjonalne sztuki programowania w języku programowania deklaratywnego.

Deklaratywny kontra imperatywny

Właściwość deklaratywna jest dziwna, tępa i trudna do uchwycenia w technicznie precyzyjnej definicji, która pozostaje ogólna i niejednoznaczna, ponieważ jest to naiwne przekonanie, że możemy zadeklarować znaczenie (aka semantyka) programu bez powodowania niezamierzonych skutków ubocznych. Istnieje nieodłączne napięcie między wyrażaniem znaczenia a unikaniem niezamierzonych efektów, a napięcie to faktycznie wywodzi się z twierdzeń o niekompletności programowania i naszego wszechświata.

Uproszczenie, nieprecyzyjne technicznie i często dwuznaczne jest definiowanie deklaratywnego jako co robić ”, a imperatywnego jako jak to zrobić . Niejednoznacznym przypadkiem jest „ co ” to „ jak ” w programie, który generuje program - kompilator.

Najwyraźniej nieograniczona rekurencja, która sprawia, że ​​język Turinga jest kompletny , jest również analogicznie w semantyce - nie tylko w składniowej strukturze oceny (czyli semantyce operacyjnej). Jest to logicznie przykład analogiczny do twierdzenia Gödla - „ każdy kompletny system aksjomatów jest również niespójny ”. Zastanów się nad sprzecznością tego cytatu! Jest to także przykład, który pokazuje, w jaki sposób wyrażenie semantyki nie ma możliwego do udowodnienia ograniczenia, dlatego nie możemy udowodnić 2, że program (i analogicznie jego semantyka) zatrzymał aka twierdzenie Haltinga.

Twierdzenia o niekompletności wywodzą się z fundamentalnej natury naszego wszechświata, który, jak stwierdzono w Drugim Prawie Termodynamiki, brzmi „ entropia (czyli # niezależnych możliwości) na zawsze osiąga maksimum ”. Kodowanie i projektowanie programu nigdy się nie kończy - żyje! - ponieważ stara się zaspokoić potrzeby świata rzeczywistego, a semantyka świata rzeczywistego ciągle się zmienia i zyskuje na popularności. Ludzie nigdy nie przestają odkrywać nowych rzeczy (w tym błędów w programach ;-).

Aby precyzyjnie i technicznie uchwycić wyżej wspomniane pożądane pojęcie w tym dziwnym wszechświecie, który nie ma krawędzi (zastanów się, że! Nie ma „na zewnątrz” naszego wszechświata), wymagana jest zwięzła, ale zwodniczo-prosta definicja, która zabrzmi nieprawidłowo, dopóki nie zostanie wyjaśniona głęboko.

Definicja:


Właściwość deklaratywna to miejsce, w którym może istnieć tylko jeden możliwy zestaw instrukcji, które mogą wyrażać każdy konkretny semantyczny moduł.

Właściwością imperatywną 3 jest dualność, w której semantyka jest niespójna w składzie i / lub może być wyrażona za pomocą odmian zestawów instrukcji.


Ta definicja deklaratywna jest wyraźnie lokalna w zakresie semantycznym, co oznacza, że ​​wymaga, aby semantyczny modułowy zachowywał swoje spójne znaczenie niezależnie od tego, gdzie i jak jest tworzony i stosowany w zakresie globalnym . Zatem każdy deklaratywny modułowy semantyczny powinien być z natury ortogonalny dla wszystkich możliwych innych - i nie być niemożliwym (z powodu twierdzeń o niekompletności) globalnym algorytmem lub modelem służącym do obserwowania spójności, co jest również punktem „ Profesora Roberta Harpera „ Więcej nie zawsze jest lepsze ” informatyki na Carnegie Mellon University, jednym z projektantów Standard ML.

Przykłady tej modułowej semantyki deklaratywnej obejmują funktory teorii kategorii, np .Applicative Typowanie nominalne, przestrzenie nazw, nazwane pola i wrt do poziomu operacyjnego semantyki, a następnie czystego programowania funkcjonalnego.

Tak więc dobrze zaprojektowane języki deklaratywne mogą wyraźniej wyrażać znaczenie , choć z pewną utratą ogólności w tym, co można wyrazić, ale zyskiem w tym, co można wyrazić z wewnętrzną spójnością.

Przykładem wyżej wymienionej definicji jest zestaw formuł w komórkach programu arkusza kalkulacyjnego - które nie powinny mieć takiego samego znaczenia po przeniesieniu do różnych komórek kolumny i wiersza, tj. Zmianie identyfikatorów komórek. Identyfikatory komórek są częścią zamierzonego znaczenia i nie są zbyteczne. Dlatego wynik każdego arkusza kalkulacyjnego jest unikalny dla identyfikatorów komórek w zestawie formuł. Spójnym semantycznym modułem w tym przypadku jest użycie identyfikatorów komórek jako danych wejściowych i wyjściowych funkcji czystych dla formuł komórek (patrz poniżej).

Hyper Text Markup Language, czyli HTML - język statycznych stron internetowych - jest przykładem bardzo (ale nie idealnie 3 ) języka deklaratywnego, który (przynajmniej przed HTML 5) nie był w stanie wyrazić zachowania dynamicznego. HTML jest chyba najłatwiejszym językiem do nauki. W celu zachowania dynamicznego imperatywny język skryptowy, taki jak JavaScript, był zwykle łączony z HTML. HTML bez JavaScript pasuje do deklaratywnej definicji, ponieważ każdy typ nominalny (tj. Tagi) zachowuje swoje spójne znaczenie w składzie zgodnie z regułami składni.

Konkurencyjną definicją deklaratywną są przemienne i idempotentne właściwości instrukcji semantycznych, tzn. Że instrukcje można zmieniać i duplikować bez zmiany znaczenia. Na przykład instrukcje przypisujące wartości do nazwanych pól mogą być ponownie uporządkowane i powielone bez zmiany znaczenia programu, jeśli te nazwy są modularne wrt w dowolnej dorozumianej kolejności. Nazwy czasami sugerują kolejność, np. Identyfikatory komórek obejmują ich pozycję kolumny i wiersza - przeniesienie sumy w arkuszu kalkulacyjnym zmienia jego znaczenie. W przeciwnym razie właściwości te domyślnie wymagają globalnegospójność semantyki. Zasadniczo niemożliwe jest zaprojektowanie semantyki instrukcji, więc pozostają one spójne, jeśli są losowo uporządkowane lub powielane, ponieważ kolejność i duplikacja są nieodłączne od semantyki. Na przykład stwierdzenia „Foo istnieje” (lub konstrukcja) i „Foo nie istnieje” (i zniszczenie). Jeśli weźmie się pod uwagę przypadkową niekonsekwencję endemiczną za zamierzoną semantykę, wówczas uznaje się tę definicję za wystarczająco ogólną dla właściwości deklaratywnej. Zasadniczo definicja ta jest pusta jako definicja uogólniona, ponieważ próbuje ona uczynić spójność ortogonalną względem semantyki, tj. Przeciwstawić się temu, że wszechświat semantyki jest dynamicznie nieograniczony i nie może być ujęty w paradygmacie globalnej spójności.

Wymaganie komutatywnych i idempotentnych właściwości (porządek oceny strukturalnej) semantyki operacyjnej niższego poziomu przekształca semantykę operacyjną w deklaratywną zlokalizowaną modularną semantyczną, np. Czyste programowanie funkcjonalne (w tym rekurencyjne zamiast pętli imperatywnych). Następnie kolejność operacyjna szczegółów implementacji nie wpływa (tj. Rozprzestrzenia się globalnie ) na spójność semantyki wyższego poziomu. Na przykład kolejność oceny (i teoretycznie także powielania) formuł arkusza kalkulacyjnego nie ma znaczenia, ponieważ dane wyjściowe nie są kopiowane do danych wejściowych, dopóki nie zostaną obliczone wszystkie dane wyjściowe, tj. Analogicznie do funkcji czystych.

C, Java, C ++, C #, PHP i JavaScript nie są szczególnie deklaratywne. Składnia Copute'a i Pythona są bardziej deklaratywnie sprzężone z zamierzonymi wynikami , tj. Spójną semantyką składniową, która eliminuje obce, dzięki czemu można łatwo zrozumieć kod po zapomnieniu. Copute i Haskell egzekwują determinizm semantyki operacyjnej i zachęcają do „ nie powtarzania się ” (DRY), ponieważ pozwalają jedynie na paradygmat funkcjonalny.


2 Nawet tam, gdzie możemy udowodnić semantykę programu, np. Za pomocą języka Coq, jest to ograniczone do semantyki wyrażanej podczas pisania , a pisanie nigdy nie może uchwycić całej semantyki programu - nawet w przypadku języków, które są niekompletność Turinga, np. HTML + CSS, można wyrazić niespójne kombinacje, które mają w ten sposób niezdefiniowaną semantykę.

3 Wiele wyjaśnień niesłusznie twierdzi, że tylko programowanie imperatywne ma składniowo uporządkowane instrukcje. Wyjaśniłem to zamieszanie między programowaniem imperatywnym a funkcjonalnym . Na przykład kolejność instrukcji HTML nie zmniejsza spójności ich znaczenia.


Edycja: Zamieściłem następujący komentarz na blogu Roberta Harpera:

w programowaniu funkcjonalnym ... zakres zmienności zmiennej jest typem

W zależności od tego, jak odróżnia się programowanie funkcjonalne od programowania imperatywnego, twoje „przypisywalne” w programie imperatywnym może również mieć typ ograniczający jego zmienność.

Jedyną niezrozumiałą definicją, którą obecnie cenię dla programowania funkcjonalnego, jest: a) funkcje jako obiekty i typy pierwszej klasy, b) preferencja dla rekurencji nad pętlami i / lub c) funkcje czyste - tj. Te funkcje, które nie wpływają na pożądaną semantykę programu po zapamiętywaniu (a zatem całkowicie czyste programowanie funkcjonalne nie istnieje w semantyce denotacyjnej ogólnego przeznaczenia z powodu wpływu semantyki operacyjnej, np. alokacji pamięci ).

Właściwość idempotentna funkcji czystej oznacza, że ​​wywołanie funkcji jej zmiennych można zastąpić jej wartością, co zwykle nie ma miejsca w przypadku argumentów procedury imperatywnej. Funkcje czyste wydają się być deklaratywne w stosunku do nieskomplikowanych przejść stanu między typami danych wejściowych i wyników.

Ale zestaw funkcji czystych nie zachowuje takiej spójności, ponieważ możliwe jest modelowanie procesu imperatywnego skutków ubocznych (stanu globalnego) w czysto funkcjonalnym języku programowania, np. IOMonad Haskella, a ponadto całkowicie niemożliwe jest zapobieganie temu dowolny całkowicie funkcjonalny język programowania Turinga.

Jak napisałem w 2012 r., Który wydaje się podobny do konsensusu komentarzy na twoim niedawnym blogu , to programowanie deklaratywne jest próbą uchwycenia pojęcia, że ​​zamierzona semantyka nigdy nie jest nieprzejrzysta. Przykładami nieprzejrzystej semantyki są zależność od porządku, zależność od usuwania semantyki wyższego poziomu w warstwie semantyki operacyjnej (np. Rzutowania nie są konwersjami, a potwierdzone generyczne ograniczają semantykę wyższego poziomu ) oraz zależność od wartości zmiennych, których nie można sprawdzić (udowodniono poprawne) według języka programowania.

Doszedłem zatem do wniosku, że tylko niekompletne języki mogą być deklaratywne.

Tak więc jednym jednoznacznym i wyraźnym atrybutem języka deklaratywnego może być to, że można udowodnić, że jego wyniki są zgodne z jakimś wymiennym zbiorem reguł generatywnych. Na przykład, dla każdego konkretnego programu HTML (ignorując różnice w sposobie rozbieżności interpretatorów), który nie jest skryptowany (tj. Nie jest kompletny w Turingu), jego zmienność wyjściowa może być policzalna. Lub bardziej zwięźle program HTML jest czystą funkcją jego zmienności. Podobnie program do obsługi arkuszy kalkulacyjnych jest czystą funkcją jego zmiennych wejściowych.

Wydaje mi się więc, że języki deklaratywne są antytezą nieograniczonej rekurencji , tzn. Według drugiego twierdzenia Gödela o samoreferencyjnych twierdzeniach nie można udowodnić.

Lesie Lamport napisała bajkę o tym, jak Euclid mógł obejść twierdzenia Gödela dotyczące niekompletności zastosowane do dowodów matematycznych w kontekście języka programowania przez zgodność między typami i logiką (korespondencja Curry-Howarda itp.).

Shelby Moore III
źródło
4

Programowanie deklaratywne to „czynność programowania w językach zgodnych z modelem mentalnym programisty, a nie z modelem operacyjnym maszyny”.

Różnicę między programowaniem deklaratywnym a imperatywnym dobrze ilustruje problem analizy danych strukturalnych.

Program imperatywny używałby wzajemnie rekurencyjnych funkcji do pobierania danych wejściowych i generowania danych. Program deklaratywny wyraziłby gramatykę, która określa strukturę danych, dzięki czemu można je następnie przeanalizować.

Różnica między tymi dwoma podejściami polega na tym, że program deklaratywny tworzy nowy język, który jest ściślej odwzorowany w modelu mentalnym problemu niż w języku goszczącym.

dan_waterworth
źródło
2

Może to zabrzmieć dziwnie, ale dodam Excela (lub dowolny arkusz kalkulacyjny) do listy systemów deklaratywnych. Dobry przykład tego podano tutaj .

Łunatik
źródło
1

Wyjaśniłbym to, ponieważ DP to sposób na wyrażenie

  • Wyrażenie cel , warunki - czego szukamy. Czy jest jeden, może lub wiele?
  • Niektóre znane fakty
  • Reguły rozszerzające znane fakty

... i tam, gdzie istnieje silnik odliczania, zwykle pracujący z algorytmem unifikacji w celu znalezienia celów.

epatel
źródło
-1

O ile wiem, zaczęto go używać do opisywania systemów programistycznych takich jak Prolog, ponieważ prolog (rzekomo) polega na deklarowaniu rzeczy w abstrakcyjny sposób.

W coraz większym stopniu oznacza to bardzo mało, ponieważ ma definicję podaną przez użytkowników powyżej. Powinno być jasne, że istnieje luka między deklaratywnym programowaniem Haskell, a w stosunku do deklaratywnego programowania HTML.

Marcin
źródło
1
Nie ma „przepaści między deklaratywnym programowaniem Haskell, a deklaratywnym programowaniem HTML”, ponieważ głównym atrybutem programowania deklaratywnego jest niezmienność przechowywanych wartości.
Shelby Moore III,
Tak czy inaczej, istnieje spora różnica między językiem specyficznym dla domeny, który jest ograniczony nawet w swoich domniemanych obliczeniach, w porównaniu z kompletnym systemem programowania.
Marcin
Zgoda. Kompletność Turinga jest ortogonalna do niezmienności przechowywanych wartości. Nie powinniśmy więc łączyć się z atrybutem deklaratywnym vs. imperatywnym. Dzięki za przemyślenie jednego z atrybutów (kompletność Turinga), które mogą powodować tę „przepaść”.
Shelby Moore III
Kompletność zwrotu wymaga tylko nieograniczonej rekurencji . Niezmienność przechowywanych wartości nie wyklucza nieograniczonej rekurencji. Są to zatem atrybuty ortogonalne.
Shelby Moore III
-2

Kilka innych przykładów programowania deklaratywnego:

  • Znaczniki ASP.Net do wiązania danych. Po prostu mówi na przykład „wypełnij tę siatkę tym źródłem” i pozostawia systemowi, jak to się dzieje.
  • Wyrażenia Linq

Programowanie deklaratywne jest przyjemne, ponieważ może uprościć twój mentalny model * kodu i może być bardziej skalowalne.

Załóżmy na przykład, że masz funkcję, która robi coś z każdym elementem tablicy lub listy. Tradycyjny kod wyglądałby tak:

foreach (object item in MyList)
{
   DoSomething(item);
}

Nic wielkiego. Ale co, jeśli użyjesz bardziej deklaratywnej składni i zamiast tego zdefiniujesz DoSomething () jako akcję? Możesz to powiedzieć w ten sposób:

MyList.ForEach(DoSometing);

Jest to oczywiście bardziej zwięzłe. Ale jestem pewien, że masz więcej obaw niż tylko zapisywanie dwóch linii kodu tu i tam. Wydajność, na przykład. Po staremu przetwarzanie musiało być wykonywane po kolei. Co zrobić, jeśli metoda .ForEach () ma sposób zasygnalizować, że może ona automatycznie przetwarzać dane równolegle? Teraz nagle twój kod jest wielowątkowy w bardzo bezpieczny sposób i zmieniłeś tylko jeden wiersz kodu. W rzeczywistości istnieje rozszerzenie .Net, które pozwala to zrobić.

  • Jeśli skorzystasz z tego linku, przeniesie Cię do posta na blogu mojego znajomego. Cały post jest trochę długi, ale możesz przewinąć w dół do nagłówka zatytułowanego „Problem” i tam go znaleźć bez problemu. *
Joel Coehoorn
źródło
1
Opisujesz programowanie funkcjonalne, a nie programowanie deklaratywne . Programowanie deklaratywne ma tę cechę, że nie mutuje przechowywanych wartości .
Shelby Moore III,
Programowanie deklaratywne może mutować przechowywane wartości ... wystarczy, że określisz (zadeklarujesz) to , co chcesz mutować, a nie dokładnie, jak to dokładnie zrobić. Jak myślisz, co jeszcze robi instrukcja SQL INSERT lub UPDATE w SQL?
Joel Coehoorn
Nie rozumiesz, że jeśli twoje funkcje nie są czyste, to niezamierzone skutki uboczne mogą zniszczyć związek między tym, co zadeklarowałeś, a faktycznym zachowaniem programu. Wyjaśniłem to bardziej szczegółowo w nowej odpowiedzi .
Shelby Moore III,
-3

To zależy od tego, jak prześlesz odpowiedź na tekst. Ogólnie rzecz biorąc, możesz spojrzeć na program w pewnym widoku, ale zależy to od tego, pod jakim kątem patrzysz na problem. Zacznę od rozpoczęcia programu: Dim Bus, Car, Time, Height As Integr

Znowu zależy to od ogólnego problemu. Być może będziesz musiał go skrócić z powodu programu. Mam nadzieję, że to pomaga i potrzebuję informacji zwrotnej, jeśli nie. Dziękuję Ci.

Danny Darrie
źródło