Es fällt mir wirklich schwer, den Unterschied zwischen prozeduralen und funktionalen Programmierparadigmen zu verstehen .
Hier sind die ersten beiden Absätze aus dem Wikipedia-Eintrag zur funktionalen Programmierung :
In der Informatik ist funktionale Programmierung ein Programmierparadigma, das Berechnung als Bewertung mathematischer Funktionen behandelt und Zustands- und veränderbare Daten vermeidet. Es betont die Anwendung von Funktionen im Gegensatz zum imperativen Programmierstil, der Zustandsänderungen betont. Die funktionale Programmierung hat ihre Wurzeln in der Lambda-Rechnung, einem formalen System, das in den 1930er Jahren entwickelt wurde, um Funktionsdefinition, Funktionsanwendung und Rekursion zu untersuchen. Viele funktionale Programmiersprachen können als Ausarbeitungen des Lambda-Kalküls angesehen werden.
In der Praxis besteht der Unterschied zwischen einer mathematischen Funktion und dem Begriff einer "Funktion", die in der imperativen Programmierung verwendet wird, darin, dass imperative Funktionen Nebenwirkungen haben können, die den Wert des Programmzustands ändern. Aus diesem Grund fehlt ihnen die referenzielle Transparenz, dh der gleiche Sprachausdruck kann je nach Status des ausführenden Programms zu unterschiedlichen Zeiten zu unterschiedlichen Werten führen. Umgekehrt hängt der Ausgabewert einer Funktion im Funktionscode nur von den Argumenten ab, die in die Funktion eingegeben werden. Wenn Sie also eine Funktion
f
zweimal mit demselben Wert für ein Argument aufrufenx
, erhalten Sie dasselbe Ergebnisf(x)
beide Male. Die Beseitigung von Nebenwirkungen kann das Verständnis und die Vorhersage des Verhaltens eines Programms erheblich erleichtern. Dies ist eine der Hauptmotive für die Entwicklung der funktionalen Programmierung.
In Absatz 2 heißt es
Umgekehrt hängt der Ausgabewert einer Funktion im Funktionscode nur von den Argumenten ab, die in die Funktion eingegeben werden. Wenn Sie also eine Funktion
f
zweimal mit demselben Wert für ein Argument aufrufen, erhalten Sie beide Malex
dasselbe Ergebnisf(x)
.
Ist das nicht genau der gleiche Fall für die prozedurale Programmierung?
Worauf sollte man bei prozeduralen und funktionalen Merkmalen achten?
Antworten:
Funktionale Programmierung
Funktionale Programmierung bezieht sich auf die Fähigkeit, Funktionen als Werte zu behandeln.
Betrachten wir eine Analogie mit "regulären" Werten. Wir können zwei ganzzahlige Werte nehmen und sie mit dem
+
Operator kombinieren , um eine neue ganze Zahl zu erhalten. Oder wir können eine Ganzzahl mit einer Gleitkommazahl multiplizieren, um eine Gleitkommazahl zu erhalten.In der funktionalen Programmierung können wir zwei Funktionswerte kombinieren, um mithilfe von Operatoren wie Compose oder Lift einen neuen Funktionswert zu erzeugen . Oder wir können einen Funktionswert und einen Datenwert kombinieren, um mithilfe von Operatoren wie map oder fold einen neuen Datenwert zu erzeugen .
Beachten Sie, dass viele Sprachen über funktionale Programmierfunktionen verfügen - auch über Sprachen, die normalerweise nicht als funktionale Sprachen angesehen werden. Sogar Großvater FORTRAN unterstützte Funktionswerte, obwohl es nicht viel an Funktionskombinationsoperatoren bot. Damit eine Sprache als "funktional" bezeichnet werden kann, müssen funktionale Programmierfunktionen in großem Umfang berücksichtigt werden.
Verfahrensprogrammierung
Prozedurale Programmierung bezieht sich auf die Fähigkeit, eine gemeinsame Folge von Anweisungen in eine Prozedur zu kapseln, so dass diese Anweisungen von vielen Stellen aus aufgerufen werden können, ohne auf Kopieren und Einfügen zurückgreifen zu müssen. Da Prozeduren eine sehr frühe Entwicklung in der Programmierung waren, ist die Fähigkeit fast immer mit dem Programmierstil verbunden, der von der maschinen- oder montagesprachlichen Programmierung gefordert wird: Ein Stil, der den Begriff der Speicherorte und Anweisungen betont, die Daten zwischen diesen Orten verschieben.
Kontrast
Die beiden Stile sind keine wirklichen Gegensätze - sie unterscheiden sich nur voneinander. Es gibt Sprachen, die beide Stile vollständig unterstützen (z. B. LISP). Das folgende Szenario vermittelt möglicherweise einen Eindruck von einigen Unterschieden zwischen den beiden Stilen. Schreiben wir einen Code für eine Unsinnanforderung, in der wir feststellen möchten, ob alle Wörter in einer Liste eine ungerade Anzahl von Zeichen haben. Erstens, prozeduraler Stil:
Ich gehe davon aus, dass dieses Beispiel verständlich ist. Nun, funktionaler Stil:
Diese Definition funktioniert von innen nach außen und bewirkt Folgendes:
compose(odd, length)
kombiniert die Funktionenodd
undlength
, um eine neue Funktion zu erstellen, die bestimmt, ob die Länge eines Strings ungerade ist.map(..., words)
ruft diese neue Funktion für jedes Element in aufwords
und gibt schließlich eine neue Liste von Booleschen Werten zurück, die jeweils angeben, ob das entsprechende Wort eine ungerade Anzahl von Zeichen hat.apply(and, ...)
Wendet den Operator "und" auf die resultierende Liste an und -ing alle Booleschen Werte zusammen, um das Endergebnis zu erhalten.Sie können diesen Beispielen entnehmen, dass es bei der prozeduralen Programmierung sehr darum geht, Werte in Variablen zu verschieben und die Operationen, die zur Erzeugung des Endergebnisses erforderlich sind, explizit zu beschreiben. Im Gegensatz dazu betont der Funktionsstil die Kombination von Funktionen, die erforderlich sind, um die anfängliche Eingabe in die endgültige Ausgabe umzuwandeln.
Das Beispiel zeigt auch die typischen relativen Größen von prozeduralem gegenüber funktionalem Code. Darüber hinaus wird gezeigt, dass die Leistungsmerkmale von Verfahrenscode möglicherweise leichter zu erkennen sind als die von Funktionscode. Bedenken Sie: Berechnen die Funktionen die Länge aller Wörter in der Liste oder stoppt jedes Wort unmittelbar nach dem Auffinden des ersten Wortes mit gerader Länge? Andererseits ermöglicht der Funktionscode einer qualitativ hochwertigen Implementierung eine ziemlich ernsthafte Optimierung, da er in erster Linie Absicht und nicht einen expliziten Algorithmus ausdrückt.
Weiterführende Literatur
Diese Frage taucht häufig auf ... siehe zum Beispiel:
In John Backus 'Vortrag zum Turing-Preis werden die Motivationen für die funktionale Programmierung ausführlich dargelegt:
Kann die Programmierung vom von Neumann-Stil befreit werden?
Ich sollte dieses Papier im gegenwärtigen Kontext wirklich nicht erwähnen, weil es ziemlich technisch wird, ziemlich schnell. Ich konnte einfach nicht widerstehen, weil ich denke, dass es wirklich grundlegend ist.
Nachtrag - 2013
Kommentatoren weisen darauf hin, dass populäre zeitgenössische Sprachen andere Programmierstile als prozedural und funktional anbieten. Solche Sprachen bieten häufig einen oder mehrere der folgenden Programmierstile:
In den Kommentaren unten finden Sie Beispiele dafür, wie die Pseudocode-Beispiele in dieser Antwort von einigen der Funktionen dieser anderen Stile profitieren können. Insbesondere wird das Verfahrensbeispiel von der Anwendung praktisch jedes übergeordneten Konstrukts profitieren.
Die ausgestellten Beispiele vermeiden bewusst das Vermischen dieser anderen Programmierstile, um die Unterscheidung zwischen den beiden diskutierten Stilen hervorzuheben.
quelle
odd_words(words)
Definition unterscheidet sich von der der AntwortallOdd
. Zum Filtern und Zuordnen werden häufig Listenverständnisse bevorzugt, aber hier soll die FunktionallOdd
eine Liste von Wörtern auf einen einzigen booleschen Wert reduzieren.Der wirkliche Unterschied zwischen funktionaler und imperativer Programmierung besteht in der Denkweise - imperative Programmierer denken an Variablen und Speicherblöcke, während funktionale Programmierer denken: "Wie kann ich meine Eingabedaten in meine Ausgabedaten umwandeln ?" - Ihr "Programm" ist die Pipeline und eine Reihe von Transformationen für die Daten , um sie von der Eingabe zur Ausgabe zu übertragen. Das ist der interessante Teil IMO, nicht das Bit "Du sollst keine Variablen verwenden".
Infolge dieser Denkweise beschreiben FP-Programme in der Regel, was passieren wird, und nicht den spezifischen Mechanismus, wie es passieren wird. Dies ist sehr effektiv, denn wenn wir klar angeben können, was "Auswählen" und "Wo" und "Aggregieren" bedeuten, sind wir es Sie können ihre Implementierungen austauschen, genau wie wir es mit AsParallel () tun, und plötzlich skaliert unsere Single-Threaded-App auf n Kerne.
quelle
Nein, da Verfahrenscode Nebenwirkungen haben kann. Beispielsweise kann der Status zwischen Anrufen gespeichert werden.
Es ist jedoch möglich, Code zu schreiben, der diese Einschränkung in prozeduralen Sprachen erfüllt. Es ist auch möglich, Code zu schreiben, der diese Einschränkung in einigen als funktionsfähig geltenden Sprachen verletzt.
quelle
Ich bin mit WReachs Antwort nicht einverstanden. Lassen Sie uns seine Antwort ein wenig dekonstruieren, um zu sehen, woher die Meinungsverschiedenheit kommt.
Erstens sein Code:
und
Das erste, was zu beachten ist, ist, dass er zusammenwächst:
Programmierung und das Fehlen der Fähigkeit zur iterativen Stilprogrammierung, einen expliziteren Kontrollfluss als ein typischer Funktionsstil zu haben.
Lassen Sie uns schnell darüber sprechen.
Ausdrucksorientierter Stil ist ein Stil, bei dem Dinge so weit wie möglich zu Dingen bewertet werden . Obwohl funktionale Sprachen für ihre Liebe zu Ausdrücken berühmt sind, ist es tatsächlich möglich, eine funktionale Sprache ohne zusammensetzbare Ausdrücke zu haben. Ich werde einen erfinden, bei dem es keine Ausdrücke gibt, nur Aussagen.
Dies ist so ziemlich das Gleiche wie zuvor, außer dass Funktionen nur durch Ketten von Anweisungen und Bindungen verkettet werden.
Ein iteratorzentrierter Programmierstil könnte von Python übernommen werden. Verwenden wir einen rein iterativen, iteratorzentrierten Stil:
Dies ist nicht funktionsfähig, da jede Klausel ein iterativer Prozess ist und sie durch explizite Pause und Wiederaufnahme der Stapelrahmen miteinander verbunden sind. Die Syntax kann teilweise von einer funktionalen Sprache inspiriert sein, wird jedoch auf eine vollständig iterative Ausführungsform davon angewendet.
Natürlich können Sie dies komprimieren:
Imperativ sieht jetzt nicht so schlecht aus, oder? :) :)
Der letzte Punkt betraf einen expliziteren Kontrollfluss. Schreiben wir den Originalcode neu, um dies zu nutzen:
Mit Iteratoren können Sie haben:
Was ist der Sinn einer funktionalen Sprache, wenn der Unterschied zwischen:
Das Hauptmerkmal einer funktionalen Programmiersprache besteht darin, dass sie Mutationen als Teil des typischen Programmiermodells entfernt. Menschen verstehen dies oft so, dass eine funktionale Programmiersprache keine Anweisungen enthält oder Ausdrücke verwendet, dies sind jedoch Vereinfachungen. Eine funktionale Sprache ersetzt die explizite Berechnung durch eine Verhaltenserklärung, für die die Sprache dann eine Reduzierung durchführt.
Wenn Sie sich auf diese Teilmenge der Funktionen beschränken, können Sie mehr Garantien für das Verhalten Ihrer Programme haben und diese freier erstellen.
Wenn Sie eine funktionale Sprache haben, ist das Erstellen neuer Funktionen im Allgemeinen so einfach wie das Erstellen eng verwandter Funktionen.
Dies ist nicht einfach oder vielleicht sogar nicht möglich, wenn Sie die globalen Abhängigkeiten einer Funktion nicht explizit gesteuert haben. Das Beste an der funktionalen Programmierung ist, dass Sie konsistentere generische Abstraktionen erstellen und darauf vertrauen können, dass sie zu einem größeren Ganzen kombiniert werden können.
quelle
apply
Vorgang nicht ganz der gleiche ist wie einfold
oderreduce
, obwohl ich der guten Fähigkeit zustimme, sehr allgemeine Algorithmen zu haben.apply
,fold
oderreduce
, aber es sieht für mich so aus, als müsste es in diesem Zusammenhang sein, damit es einen Booleschen Wert zurückgibt.Im prozeduralen Paradigma (soll ich stattdessen "strukturierte Programmierung" sagen?) Haben Sie veränderlichen Speicher und Anweisungen geteilt, die ihn in einer bestimmten Reihenfolge (nacheinander) lesen / schreiben.
Im Funktionsparadigma haben Sie Variablen und Funktionen (im mathematischen Sinne: Variablen variieren nicht über die Zeit, Funktionen können nur etwas basierend auf ihren Eingaben berechnen).
(Dies ist zu stark vereinfacht, z. B. verfügen FPLs normalerweise über Funktionen zum Arbeiten mit veränderlichem Speicher, während prozedurale Sprachen häufig Verfahren höherer Ordnung unterstützen, sodass die Dinge nicht so eindeutig sind. Dies sollte Ihnen jedoch eine Idee geben.)
quelle
Das charmante Python: Die funktionale Programmierung in Python von IBM Developerworks hat mir wirklich geholfen, den Unterschied zu verstehen.
Insbesondere für jemanden, der Python ein wenig kennt, können die Codebeispiele in diesem Artikel, in denen verschiedene Dinge funktional und prozedural kontrastiert werden, den Unterschied zwischen prozeduraler und funktionaler Programmierung verdeutlichen.
quelle
In der funktionalen Programmierung müssen Sie nur zwei Dinge wissen, um über die Bedeutung eines Symbols (Variablen- oder Funktionsname) nachzudenken - den aktuellen Umfang und den Namen des Symbols. Wenn Sie eine rein funktionale Sprache mit Unveränderlichkeit haben, handelt es sich bei beiden Konzepten um "statische" Konzepte (Entschuldigung für stark überladene Namen). Dies bedeutet, dass Sie beide - den aktuellen Bereich und den Namen - nur anhand des Quellcodes anzeigen können.
Wenn Sie in der prozeduralen Programmierung die Frage beantworten möchten, was der Wert dahinter ist, müssen
x
Sie auch wissen, wie Sie dorthin gekommen sind. Umfang und Name allein reichen nicht aus. Und dies ist das, was ich als die größte Herausforderung ansehen würde, da dieser Ausführungspfad eine "Laufzeit" -Eigenschaft ist und von so vielen verschiedenen Dingen abhängen kann, dass die meisten Leute lernen, ihn nur zu debuggen und nicht zu versuchen, den Ausführungspfad wiederherzustellen.quelle
Ich habe kürzlich über den Unterschied in Bezug auf das Ausdrucksproblem nachgedacht . Phil Wadlers Beschreibung wird oft zitiert, aber die akzeptierte Antwort auf diese Frage ist wahrscheinlich leichter zu befolgen. Grundsätzlich scheint es, dass imperative Sprachen dazu neigen, einen Ansatz für das Problem zu wählen, während funktionale Sprachen dazu neigen, den anderen zu wählen.
quelle
Ein klarer Unterschied zwischen den beiden Programmierparadigmen ist der Zustand.
In der funktionalen Programmierung wird der Status vermieden. Einfach ausgedrückt, es wird keine Variable geben, der ein Wert zugewiesen ist.
Beispiel:
Die prozedurale Programmierung verwendet jedoch den Status.
Beispiel:
quelle