482 Stimmen

Funktionale, deklarative und imperative Programmierung

Was bedeuten die Begriffe funktionale, deklarative und imperative Programmierung?

4 Stimmen

Hier gibt es einige gute Antworten. Eine interessante Sache, die nicht vollständig geklärt wurde, ist, dass deklarativ et Imperativ sind komplementär und symbiotisch, mehr als nur unterschiedliche Stile oder was vs. wie .

1 Stimmen

@Kit Imo, einige der Antworten auf dieser Seite verwechseln die Begriffe. DP == referentielle Transparenz (RT). DP & IP sind Gegensätze, also afaics nicht Ergänzungen eines Ganzen, d.h. ein ganzes Programm kann in beiden Stilen geschrieben werden. Der Aufruf einer Funktion kann entweder DP (RT) oder IP sein, ihre Implementierung kann beides sein oder eine Mischung daraus. Sie sind nicht symbiotisch in dem Sinne, dass ein Aufruf einer IP-Funktion in einer ansonsten DP-Funktion den Aufruf der DP-Funktion zu IP machen kann. Sie sind symbiotisch in dem Sinne, dass reale (z. B. funktional reaktive) Programme eine Mischung verwenden können, z. B. IP-Aufrufe auf oberster Ebene in DP-Funktionen.

1 Stimmen

Sollte in das Wiki aufgenommen werden oder ein Link auf etwas Ähnliches wie das Wiki usw. Hier ist ein toller Link in Wikipedia de.wikipedia.org/wiki/Vergleich_von_Programmierparadigmen

274voto

Shelby Moore III Punkte 5909

Zum Zeitpunkt der Erstellung dieses Artikels sind die am häufigsten gewählten Antworten auf dieser Seite ungenau und verworren in Bezug auf die Definition von deklarativ und imperativ, einschließlich der Antwort, die Wikipedia zitiert. In einigen Antworten werden die Begriffe auf unterschiedliche Weise miteinander vermischt.

Siehe auch meine Erklärung warum die Programmierung von Tabellenkalkulationen deklarativ ist, unabhängig davon, dass die Formeln die Zellen verändern.

Außerdem wird in mehreren Antworten behauptet, dass die funktionale Programmierung eine Teilmenge der deklarativen Programmierung sein muss. In diesem Punkt hängt es davon ab, ob wir "Funktion" von "Prozedur" unterscheiden. Behandeln wir zunächst den Unterschied zwischen imperativ und deklarativ.

Definition von deklarativer Ausdruck

El sólo Attribut, das möglicherweise eine Unterscheidung zwischen deklarativ Ausdruck aus einer Imperativ Ausdruck ist die referenzielle Transparenz (RT) seiner Unterausdrücke. Alle anderen Attribute werden entweder von beiden Arten von Ausdrücken gemeinsam genutzt oder von der RT abgeleitet.

Eine 100% deklarative Sprache (d.h. eine, in der jeder mögliche Ausdruck RT ist) erlaubt (neben anderen RT-Anforderungen) nicht die Mutation gespeicherter Werte, z.B. HTML und der größte Teil von Haskell.

Definition von RT-Ausdruck

Die RT wird oft als "nebenwirkungsfrei" bezeichnet. Der Begriff Auswirkungen hat keine genaue Definition, so dass einige Leute nicht damit einverstanden sind, dass "keine Nebenwirkungen" dasselbe ist wie RT. RT hat eine genaue Definition :

Ein Ausdruck e ist referenziell transparent, wenn für alle Programme p jedes Vorkommen von e en p kann durch das Ergebnis der Auswertung von e , ohne das beobachtbare Ergebnis von p .

Da jeder Unterausdruck konzeptionell ein Funktionsaufruf ist, verlangt RT, dass die Implementierung einer Funktion (d. h. der Ausdruck/die Ausdrücke innerhalb der aufgerufenen Funktion) nicht auf den veränderlichen Zustand zugreifen darf, der extern zur Funktion (Zugriff auf die änderbar . Staat erlaubt ist). Vereinfacht ausgedrückt, sollte die Funktion (Implementierung) sein rein .

Definition von reine Funktion

Von einer reinen Funktion wird oft gesagt, dass sie "keine Nebeneffekte" hat. Der Begriff Auswirkungen hat keine genaue Definition, so dass manche Leute damit nicht einverstanden sind.

Reine Funktionen haben die folgenden Eigenschaften.

  • die einzige beobachtbare Ausgabe ist der Rückgabewert.
  • die einzige Abhängigkeit von der Ausgabe sind die Argumente.
  • Argumente vollständig bestimmt werden, bevor eine Ausgabe erzeugt wird.

Denken Sie daran, dass RT für Ausdrücke (einschließlich Funktionsaufrufe) und Reinheit für (Implementierungen von) Funktionen gilt.

Ein obskures Beispiel für unreine Funktionen, die RT-Ausdrücke bilden, ist die Gleichzeitigkeit, aber das liegt daran, dass die Reinheit auf der Unterbrechungsabstraktionsschicht gebrochen wird. Das brauchen Sie nicht wirklich zu wissen. Um RT-Ausdrücke zu erstellen, rufen Sie reine Funktionen auf.

Abgeleitete Attribute der RT

Jedes andere Attribut, das für die deklarative Programmierung genannt wird, z. B. das Zitat von 1999 von Wikipedia verwendet wird, entweder von der RT abgeleitet oder mit der imperativen Programmierung geteilt wird. Damit ist bewiesen, dass meine genaue Definition richtig ist.

Anmerkung: Unveränderlichkeit von externe Werte ist eine Teilmenge der Anforderungen für RT.

  • Deklarative Sprachen haben keine Kontrollstrukturen mit Schleifen, z. B. for y while porque aufgrund der Unveränderlichkeit würde sich die Schleifenbedingung nie ändern.

  • Deklarative Sprachen drücken keinen anderen Kontrollfluss aus als die Reihenfolge verschachtelter Funktionen (auch bekannt als logische Abhängigkeiten), weil aufgrund der Unveränderlichkeit Wenn Sie eine andere Auswertungsreihenfolge wählen, ändert sich das Ergebnis nicht (siehe unten).

  • Deklarative Sprachen drücken logische "Schritte" aus (d.h. die Reihenfolge der verschachtelten RT-Funktionsaufrufe), aber ob jeder Funktionsaufruf eine höhere semantische Ebene darstellt (d.h. "was zu tun ist"), ist keine Anforderung der deklarativen Programmierung. Der Unterschied zum Imperativ besteht darin, dass aufgrund der Unveränderlichkeit (d.h. allgemeiner RT) können diese "Schritte" nicht von einem veränderlichen Zustand abhängen, sondern nur von der relationalen Reihenfolge der ausgedrückten Logik (d.h. der Reihenfolge der Verschachtelung der Funktionsaufrufe, auch bekannt als Unterausdrücke).

Zum Beispiel, der HTML-Absatz <p> kann erst angezeigt werden, wenn die Unterausdrücke (d. h. Tags) im Absatz ausgewertet wurden. Es gibt keinen veränderlichen Zustand, sondern nur eine Ordnungsabhängigkeit aufgrund der logischen Beziehung der Tag-Hierarchie (Verschachtelung von Unterausdrücken, die analog verschachtelte Funktionsaufrufe ).

  • So gibt es das abgeleitete Attribut der Unveränderlichkeit (allgemeiner: RT), dass deklarative Ausdrücke, die sólo le site logisch Beziehungen der Bestandteile (d. h. der Funktionsargumente der Unterausdrücke) und nicht veränderlicher Zustand Beziehungen.

Bewertungsauftrag

Die Wahl der Auswertungsreihenfolge von Teilausdrücken kann nur dann zu einem abweichenden Ergebnis führen, wenn einer der Funktionsaufrufe nicht RT ist (d. h. die Funktion ist nicht rein), z. B. wenn innerhalb der Funktion auf einen veränderlichen Zustand außerhalb der Funktion zugegriffen wird.

Ein Beispiel: Bei einigen verschachtelten Ausdrücken, z. B. f( g(a, b), h(c, d) ) Die eifrige und die faule Auswertung der Funktionsargumente führen zu denselben Ergebnissen, wenn die Funktionen f , g y h sind rein.

Wenn die Funktionen f , g y h nicht rein sind, dann kann die Wahl der Auswertungsreihenfolge zu einem anderen Ergebnis führen.

Beachten Sie, dass verschachtelte Ausdrücke konzeptionell verschachtelte Funktionen sind, da Ausdrucksoperatoren nur Funktionsaufrufe sind, die sich als unäres Präfix, unäres Postfix oder binäre Infix-Notation tarnen.

Tangential, wenn alle Identifikatoren, z.B. a , b , c , d sind unveränderlich Überall dort, wo auf programmfremde Zustände nicht zugegriffen werden kann (z. B. E/A) und keine Abstraktionsschicht unterbrochen wird, sind die Funktionen immer rein.

Übrigens, Haskell hat eine andere Syntax, f (g a b) (h c d) .

Details zum Bewertungsauftrag

Eine Funktion ist ein Zustandsübergang (kein veränderlicher gespeicherter Wert) von der Eingabe zur Ausgabe. Für RT-Kompositionen von Aufrufen zu rein Funktionen ist die Reihenfolge der Ausführung dieser Zustandsübergänge unabhängig. Der Zustandsübergang eines jeden Funktionsaufrufs ist unabhängig von den anderen, da es keine Seiteneffekte gibt und der Grundsatz gilt, dass ein RT-Funktion kann durch ihren zwischengespeicherten Wert ersetzt werden . An ein verbreitetes Missverständnis zu korrigieren ist die reine monadische Komposition immer deklarativ und RT trotz der Tatsache, dass Haskell's IO Monade ist wohl unrein und damit zwingend erforderlich in Bezug auf die World Zustand außerhalb des Programms (aber im Sinne des nachstehenden Vorbehalts sind die Nebeneffekte isoliert).

Eifrige Auswertung bedeutet, dass die Funktionsargumente ausgewertet werden, bevor die Funktion aufgerufen wird, und faule Auswertung bedeutet, dass die Argumente werden nicht ausgewertet bis (und wenn) auf sie innerhalb der Funktion zugegriffen wird.

Definition Funktion Parameter werden in der Funktion Definition Standort und Funktion Argumente werden bei der Funktion aufrufen Standort. Kennen Sie den Unterschied zwischen Parameter y Argument .

Konzeptionell sind alle Ausdrücke (eine Zusammensetzung von) Funktionsaufrufen, z. B. sind Konstanten Funktionen ohne Eingaben, unäre Operatoren sind Funktionen mit einer Eingabe, binäre Infix-Operatoren sind Funktionen mit zwei Eingaben, Konstruktoren sind Funktionen und sogar Steueranweisungen (z. B. if , for , while ) können mit Funktionen modelliert werden. Die anordnen, dass diese Argument Funktionen (nicht zu verwechseln mit verschachtelten Funktionsaufrufen) ausgewertet werden, wird nicht durch die Syntax angegeben, z. B. f( g() ) könnte eifrig bewerten g dann f auf g Ergebnis auswerten oder es könnte f und bewerten nur faul g wenn sein Ergebnis innerhalb von f .

Vorbehalt, nein Turing vollständig Sprache (d.h. die unbeschränkte Rekursion zulässt) vollkommen deklarativ ist, führt z.B. die faule Auswertung zu Speicher- und Zeitindeterminismus. Diese durch die Wahl der Auswertungsreihenfolge bedingten Nebeneffekte beschränken sich jedoch auf den Speicherverbrauch, die Ausführungszeit, die Latenzzeit, den Nichtabbruch und externe Hysterese also externe Synchronisation.

Funktionale Programmierung

Da es bei der deklarativen Programmierung keine Schleifen geben kann, ist die einzige Möglichkeit der Iteration die funktionale Rekursion. In diesem Sinne ist die funktionale Programmierung mit der deklarativen Programmierung verwandt.

Pero die funktionale Programmierung ist nicht auf die deklarative Programmierung beschränkt . Die funktionale Zusammensetzung kann sein im Gegensatz zur Subtypisierung insbesondere in Bezug auf die Ausdruck Problem wobei die Erweiterung erreicht werden kann durch entweder durch Hinzufügen von Subtypen oder durch funktionale Zerlegung . Erweiterung kann eine Mischung sein der beiden Methoden.

In der funktionalen Programmierung ist die Funktion in der Regel ein Objekt erster Klasse, d. h. der Funktionstyp kann in der Grammatik überall dort auftauchen, wo auch jeder andere Typ auftauchen kann. Das Ergebnis ist, dass Funktionen Funktionen eingeben und auf Funktionen operieren können, wodurch die Trennung von Problemen durch die Betonung der Funktionskomposition ermöglicht wird, d. h. die Trennung der Abhängigkeiten zwischen den Teilberechnungen einer deterministischen Berechnung.

Zum Beispiel, anstatt eine eigene Funktion zu schreiben (und unter Verwendung von Rekursion anstelle von Schleifen, wenn die Funktion auch deklarativ sein muss) für jede der unendlich vielen möglichen spezialisierten Aktionen, die auf jedes Element einer Sammlung angewendet werden könnten, verwendet die funktionale Programmierung wiederverwendbare Iterationsfunktionen, z. B. map , fold , filter . Diese Iterationsfunktionen geben eine spezialisierte Aktionsfunktion erster Klasse ein. Diese Iterationsfunktionen iterieren die Sammlung und rufen die eingegebene spezialisierte Aktionsfunktion für jedes Element auf. Diese Aktionsfunktionen sind prägnanter, da sie keine Schleifenanweisungen mehr enthalten müssen, um die Sammlung zu iterieren.

Beachten Sie jedoch, dass es sich bei einer Funktion, die nicht rein ist, um eine Prozedur handelt. Wir können vielleicht argumentieren, dass funktionale Programmierung, die unreine Funktionen verwendet, in Wirklichkeit prozedurale Programmierung ist. Wenn wir also zustimmen, dass deklarative Ausdrücke RT sind, dann können wir sagen, dass prozedurale Programmierung nicht deklarative Programmierung ist, und so könnten wir argumentieren, dass funktionale Programmierung immer RT ist und eine Teilmenge der deklarativen Programmierung sein muss.

Parallelität

Diese funktionale Komposition mit Funktionen erster Klasse kann die Tiefe in der Parallelität indem die unabhängige Funktion herausgetrennt wird.

Brentsches Prinzip: Berechnungen mit Arbeit w und Tiefe d können in einem PRAM mit p-Prozessoren in der Zeit O(max(w/p, d)) durchgeführt werden.

Sowohl Gleichzeitigkeit als auch Parallelität eine deklarative Programmierung erfordern d.h. Unveränderlichkeit und RT.

Woher kommt also die gefährliche Annahme, dass Parallelität = Gleichzeitigkeit bedeutet? herkommt? Das ist eine natürliche Folge von Sprachen mit Seiteneffekten: Wenn Ihre Sprache überall Nebeneffekte hat, dann müssen Sie jedes Mal, wenn Sie versuchen mehr als eine Sache zur gleichen Zeit zu tun, haben Sie im Grunde Nicht-Determinismus, der durch die Verschachtelung der Effekte der einzelnen Operation. In Sprachen mit Seiteneffekten ist also die einzige Möglichkeit, Parallelität zu erreichen Parallelität zu erreichen; es ist daher nicht überraschend, dass wir dass wir die beiden oft vermischt sehen.

FP-Bewertungsauftrag

Beachten Sie, dass die Auswertungsreihenfolge auch Auswirkungen auf die Beendigung und die Leistungsnebeneffekte der funktionalen Komposition hat.

Eifrige (CBV) und faule (CBN) sind kategorische Duelle[ 10 ], weil sie eine umgekehrte Auswertungsreihenfolge haben, d.h. ob die äußeren oder inneren Funktionen zuerst ausgewertet werden. Stellen Sie sich einen auf dem Kopf stehenden Baum vor, dann wird eager von den Zweigspitzen des Funktionsbaums die Zweighierarchie hinauf bis zum Funktionsstamm der obersten Ebene ausgewertet, während lazy vom Stamm abwärts bis zu den Zweigspitzen ausgewertet wird. Eager kennt keine konjunktiven Produkte ("und", auch bekannt als kategorische "Produkte") und lazy kennt keine disjunktiven Koprodukte ("oder", auch bekannt als kategorische "Summen")[ 11 ].

Leistung

  • Eifrig

Wie bei der Nichtterminierung ist eager bei der konjunktiven funktionalen Komposition zu eifrig, d. h. die kompositionale Kontrollstruktur leistet unnötige Arbeit, die mit lazy nicht erledigt wird. Für Beispiel wird die gesamte Liste eifrig und unnötigerweise auf Boolesche Werte abgebildet, wenn sie mit einer Faltung zusammengestellt wird, die am ersten wahren Element endet.

Diese unnötige Arbeit ist die Ursache für die angegebenen "bis zu" zusätzlichen Kosten log n-Faktor in der sequentiellen Zeitkomplexität von eager versus lazy, beide mit reinen Funktionen. Eine Lösung besteht in der Verwendung von Funktoren (z. B. Listen) mit lazy-Konstruktoren (d. h. eager mit optionalen lazy-Produkten), da bei eager die Unrichtigkeit des Eifers von der inneren Funktion ausgeht. Dies liegt daran, dass Produkte konstruktive Typen sind, d. h. induktive Typen mit einer Anfangsalgebra auf einem Anfangsfixpunkt[ 11 ]

  • Faule

Wie bei der Non-Terminierung ist lazy bei der disjunktiven funktionalen Komposition zu faul, d.h. die koinduktive Finalität kann später als nötig eintreten, was sowohl zu unnötiger Arbeit als auch zur Nicht-Determiniertheit der Verspätung führt, was bei eager nicht der Fall ist[ 10 ][ 11 ]. Beispiele für Endgültigkeit sind Zustand, Zeitplanung, Nichtbeendigung und Laufzeitausnahmen. Dies sind imperative Nebeneffekte, aber selbst in einer rein deklarativen Sprache (z.B. Haskell) gibt es einen Zustand in der imperativen IO-Monade (Achtung: nicht alle Monaden sind imperativ!), implizit in der Raumzuweisung, und das Timing ist ein Zustand relativ zur imperativen realen Welt. Die Verwendung von lazy, selbst mit optionalen eager-Koprodukten, führt dazu, dass die "Faulheit" in die inneren Koprodukte übergeht, da bei lazy die Unkorrektheit der Faulheit stammt aus der äußeren Funktion (siehe das Beispiel im Abschnitt Nicht-Terminierung, wo == eine äußere binäre Operatorfunktion ist). Dies liegt daran, dass Koprodukte durch Finalität begrenzt sind, d. h. koinduktive Typen mit einer finalen Algebra auf ein finales Objekt[ 11 ].

Lazy verursacht Indeterminismus beim Entwurf und der Fehlersuche von Funktionen für Latenz und Raum, deren Fehlersuche wahrscheinlich die Fähigkeiten der meisten Programmierer übersteigt, da die Dissonanz zwischen die deklarierte Funktionshierarchie und die Reihenfolge der Auswertung zur Laufzeit. Reine Lazy-Funktionen, die mit Eager ausgewertet werden, können möglicherweise zu einem bisher nicht beobachteten Nicht-Abbruch zur Laufzeit führen. Umgekehrt könnten reine eager-Funktionen, die mit lazy ausgewertet werden, zur Laufzeit einen bisher nicht gesehenen Raum- und Latenzindeterminismus einführen.

Nichtkündigung

Zur Kompilierzeit kann aufgrund des Halting-Problems und der gegenseitigen Rekursion in einer vollständigen Turing-Sprache im Allgemeinen nicht garantiert werden, dass die Funktionen enden.

  • Eifrig

Mit eifrig, aber nicht faul, für die Verbindung von Head "und" Tail wenn entweder Head o Tail nicht abbricht, dann wird entweder List( Head(), Tail() ).tail == Tail() o List( Head(), Tail() ).head == Head() ist nicht wahr, weil die linke Seite nicht endet und die rechte Seite schon.

Bei Faulheit hingegen enden beide Seiten. Daher ist eager bei konjunktiven Produkten zu eifrig und terminiert nicht (einschließlich Laufzeitausnahmen) in den Fällen, in denen es nicht notwendig ist.

  • Faule

Mit faul, aber nicht begierig, auf die Disjunktion von 1 "oder" 2 , si f nicht beendet wird, dann List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail ist nicht wahr, weil die linke Seite abbricht und die rechte nicht.

Bei eager hingegen bricht keine der beiden Seiten ab, so dass der Gleichheitstest nie erreicht wird. Daher ist lazy bei disjunktiven Koprodukten zu träge und bricht in diesen Fällen nicht ab (einschließlich Laufzeitausnahmen), nachdem es mehr Arbeit gemacht hat, als es eager getan hätte.

[ 10 ] Declarative Continuations and Categorical Duality, Filinski, Abschnitte 2.5.4 A comparison of CBV and CBN, und 3.6.1 CBV and CBN in the SCL.

[ 11 ] Declarative Continuations and Categorical Duality, Filinski, Abschnitte 2.2.1 Products and coproducts, 2.2.2 Terminal and initial objects, 2.5.2 CBV with lazy products, and 2.5.3 CBN with eager coproducts.

0 Stimmen

Auch bei der deklarativen Constraint-Programmierung ändern sich die Constraints nicht, während der Solver die Lösung findet. Das liegt auf der Hand, denn es gibt keine Möglichkeit, einen Zeitpunkt für ihre Änderung anzugeben. Selbst Einschränkungen, die in Bezug auf andere Einschränkungen spezifiziert werden, werden alle angegeben, bevor der Solver ausgeführt wird, um die Lösung zu finden. Dies ist analog zu den deklarativen Formeln in der Tabellenkalkulation .

3 Stimmen

Eine Abkürzung bedeutet nicht, dass eine Definition angegeben wird. Wenn ich schreibe: "RT wird oft mit 'keine Nebenwirkungen' abgekürzt", bedeutet das nicht, dass die Definition von RT "keine Nebenwirkungen" ist, denn die Menschen können unterschiedliche Definitionen für "Auswirkungen" haben. Wenn ich stattdessen gesagt hätte: "RT wird oft mit 'xyz' abgekürzt", würde ein bedeutungsloses Symbol keine Definition für RT liefern. RT hat eine genau Definition das sich nie ändert, ganz gleich, welches Symbol man dafür verwendet.

0 Stimmen

Ich kann kein Gegenbeispiel zu meiner Behauptung finden, dass jede Art von DP RT ist. Zum Beispiel ändert sich die Bedeutung (d.h. der Wert) der Begriffe einer kontextsensitiven Grammatik nicht zu einem anderen Zeitpunkt oder an einer anderen Stelle innerhalb der Grammatik. Siehe meinen obigen Kommentar zur Constraint-Programmierung.

106voto

Jason Baker Punkte 180981

Es gibt eigentlich keine eindeutige, objektive Definition für sie. Hier ist wie I würde sie definieren:

Imperativ - Der Schwerpunkt liegt darauf, welche Schritte der Computer unternehmen sollte, und nicht darauf, was der Computer tun wird. tun (z. B. C, C++, Java).

Deklarativ - Der Schwerpunkt liegt auf dem, was der Computer tun soll, und nicht darauf, wie er es tun soll (z. B. SQL).

Funktionell - eine Untergruppe der deklarativen Sprachen, die sich stark auf die Rekursion konzentriert

0 Stimmen

Die Rekursion ist nicht das einzige Merkmal funktionaler Sprachen. Sie haben auch andere Möglichkeiten, mit Funktionen umzugehen als nur die Kompilierung, z. B. die Kombination von Funktionen zur Laufzeit, um eine neue Funktion zu erhalten.

1 Stimmen

Behalten Sie einige Dinge im Auge: 1) Die Erklärung soll einfach und nicht allumfassend sein. 2) Wie ich bereits sagte, gibt es mehrere Möglichkeiten, diese Sprachen zu definieren. Daher kann die Antwort für Sie sehr wohl falsch und für jemand anderen richtig sein.

3 Stimmen

Funktionale Programmierung ist no "eine Teilmenge der deklarativen Sprachen". Die deklarative Programmierung erfordert die Unveränderlichkeit der gespeicherten Werte, die funktionale Programmierung nicht, wenn sie nicht rein FP. Siehe meine Antwort . Siehe auch die Erklärung für Tabellenkalkulationszellen . Die richtige Zielsetzung Definitionen sind nicht "zweideutig". Auch bei der imperativen Programmierung geht es darum, "was der Computer tun soll". Die seulement Die Unterscheidung ist zwingend erforderlich, da die Programmierung mit veränderlichen gespeicherten Werten umgehen muss.

62voto

andrew cooke Punkte 43891

Imperativ y deklarativ Beschreiben Sie zwei gegensätzliche Programmierstile. Imperativ ist der traditionelle "Schritt-für-Schritt-Rezept"-Ansatz, während deklarativ eher "das ist es, was ich will, und jetzt finden Sie heraus, wie man es macht" ist.

diese beiden ansätze kommen in der gesamten programmierung vor - sogar in ein und derselben sprache und ein und demselben programm. im allgemeinen wird der deklarative ansatz als vorteilhaft angesehen, da er den programmierer davon befreit, so viele details angeben zu müssen, und gleichzeitig die gefahr von Fehlern verringert (wenn man das gewünschte ergebnis beschreibt und ein gut getesteter automatischer prozess davon ausgehend die schritte definieren kann, kann man hoffen, dass die dinge zuverlässiger sind, als wenn man jeden schritt von hand angeben muss).

andererseits bietet ein imperativer ansatz mehr Kontrolle auf niedriger ebene - es ist der "mikromanager-ansatz" der programmierung. und das kann es dem programmierer ermöglichen, das wissen über das problem auszunutzen, um eine effizientere antwort zu geben. es ist also nicht ungewöhnlich, dass einige teile eines programms in einem eher deklarativen stil geschrieben sind, aber die geschwindigkeitskritischen teile eher imperativ.

Wie Sie sich vielleicht vorstellen können, hat die Sprache, die Sie zum Schreiben eines Programms verwenden, einen Einfluss darauf, wie deklarativ Sie sein können - eine Sprache, die über eingebaute "Intelligenz" verfügt, um herauszufinden, was angesichts einer Beschreibung des Ergebnisses zu tun ist, ermöglicht einen viel deklarativeren Ansatz als eine Sprache, bei der der Programmierer diese Art von Intelligenz zunächst mit imperativem Code hinzufügen muss, bevor er eine deklarativere Schicht darauf aufbauen kann. so wird zum Beispiel eine Sprache wie Prolog als sehr deklarativ angesehen, weil sie über einen integrierten Prozess verfügt, der nach Antworten sucht.

Sie werden feststellen, dass ich bis jetzt noch nicht erwähnt habe, dass funktionell programmierung. das liegt daran, dass es ein begriff ist, dessen bedeutung nicht unmittelbar mit den anderen beiden zusammenhängt. in seiner einfachsten form bedeutet funktionale programmierung, dass man funktionen verwendet. insbesondere, dass man eine sprache verwendet, die funktionen als "werte erster klasse" unterstützt - das bedeutet, dass man nicht nur funktionen schreiben kann, sondern auch funktionen, die funktionen schreiben (die funktionen schreiben, die...), und funktionen an funktionen übergeben können. kurz gesagt - dass funktionen so flexibel und verbreitet sind wie strings und zahlen.

es mag seltsam erscheinen, dass funktional, imperativ und deklarativ oft zusammen erwähnt werden. der grund dafür ist eine folge davon, dass man die idee der funktionalen programmierung "auf die Spitze treibt". eine funktion, in ihrem reinsten sinn, ist etwas aus der mathematik - eine art "black box", die eine eingabe annimmt und immer die gleiche ausgabe liefert. Wenn Sie also eine Programmiersprache entwerfen, deren Ziel es ist, eine sehr reine, mathematisch geprägte Idee der funktionalen Programmierung zu implementieren, lehnen Sie die Idee von Werten, die sich ändern können (in einem bestimmten, begrenzten, technischen Sinn), weitgehend ab.

Und wenn man das tut - wenn man einschränkt, wie sich Variablen ändern können - dann zwingt man den Programmierer fast zufällig dazu, Programme zu schreiben, die deklarativer sind, weil ein großer Teil der imperativen Programmierung darin besteht, zu beschreiben, wie sich Variablen ändern, und das kann man nicht mehr tun! Es stellt sich also heraus, dass funktionale Programmierung - insbesondere die Programmierung in einer funktionalen Sprache - eher zu deklarativem Code führt.

um es zusammenzufassen:

  • Imperativ und deklarativ sind zwei gegensätzliche Programmierstile (die gleichen Namen werden für Programmiersprachen verwendet, die diese Stile fördern)

  • funktionale programmierung ist ein programmierstil, bei dem funktionen sehr wichtig werden und infolgedessen die änderung von werten weniger wichtig wird. die begrenzte möglichkeit, änderungen von werten zu spezifizieren, zwingt zu einem eher deklarativen stil.

Daher wird die "funktionale Programmierung" oft als "deklarativ" bezeichnet.

7 Stimmen

Die beste Erklärung bisher. Es scheint, dass Functional und OOP orthogonal zu Imperative und Declarative sind.

0 Stimmen

Würden Sie sagen, dass logische Programmierung deklarativ ist? Oder ist sie selbst orthogonal?

51voto

mdja Punkte 695

Kurz und bündig:

Eine zwingende Sprache gibt eine Reihe von Anweisungen an, die der Computer nacheinander ausführt (tu dies, dann tu das).

A deklarative Sprache deklariert eine Reihe von Regeln darüber, welche Ausgaben aus welchen Eingaben resultieren sollten (z.B. wenn Sie A haben, dann ist das Ergebnis B). Eine Maschine wendet diese Regeln auf die Eingaben an und gibt eine Ausgabe aus.

A funktionelle Sprache deklariert eine Reihe von mathematischen/logischen Funktionen, die festlegen, wie die Eingabe in eine Ausgabe umgewandelt wird. z.B. f(y) = y * y. Es handelt sich um eine Art von deklarativer Sprache.

1 Stimmen

Funktionale Programmierung ist no "eine Art deklarative Sprache". Die deklarative Programmierung erfordert die Unveränderlichkeit der gespeicherten Werte, unrein die funktionale Programmierung nicht. Siehe meine Antwort . Siehe auch die Erklärung für Tabellenkalkulationszellen . Die seulement Der Grund dafür, dass imperative Logik (d.h. Anweisungen) nacheinander ausgeführt werden, ist, dass das Ergebnis aufgrund des Vorhandenseins veränderlicher gespeicherter Werte von der Auswertungsreihenfolge abhängig ist. Nach Ihrem Vokabular kann eine "Anweisung" (und eine "Regel" nicht) mit veränderlichen Werten arbeiten.

25voto

Arturo Herrero Punkte 12142

Imperativ: wie um unser Ziel zu erreichen

   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

Deklarativ: was die wir erreichen wollen

   Show customer details of every customer living in Spain

0 Stimmen

Sie beschreiben funktionale Programmierung vs. Nicht-FP, nicht deklarative vs. imperative Programmierung. Funktionale Programmierung ist orthogonal zur Polarität zwischen imperativer und deklarativer Programmierung. Die deklarative Programmierung erfordert die Unveränderlichkeit der gespeicherten Werte, unrein die funktionale Programmierung nicht. Siehe meine Antwort .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X