Was ist der Unterschied zwischen prozeduraler Programmierung und funktionaler Programmierung? [geschlossen]

247

Ich habe die Wikipedia-Artikel sowohl zur prozeduralen als auch zur funktionalen Programmierung gelesen , bin aber immer noch etwas verwirrt. Könnte es jemand auf den Punkt bringen?

Thomas Owens
quelle
Wikipedia impliziert, dass FP eine Teilmenge der deklarativen Programmierung ist (dh immer ist), aber das ist nicht wahr und bringt die Taxonomie von IP vs. DP in Konflikt .
Shelby Moore III

Antworten:

152

Mit einer funktionalen Sprache können Sie (idealerweise) eine mathematische Funktion schreiben, dh eine Funktion, die n Argumente akzeptiert und einen Wert zurückgibt. Wenn das Programm ausgeführt wird, wird diese Funktion nach Bedarf logisch ausgewertet. 1

Eine prozedurale Sprache führt andererseits eine Reihe von aufeinanderfolgenden Schritten aus. (Es gibt eine Möglichkeit, sequentielle Logik in funktionale Logik umzuwandeln, die als Continuation-Passing-Stil bezeichnet wird .)

Infolgedessen liefert ein rein funktionales Programm immer den gleichen Wert für eine Eingabe, und die Reihenfolge der Auswertung ist nicht genau definiert. Dies bedeutet, dass unsichere Werte wie Benutzereingaben oder Zufallswerte in rein funktionalen Sprachen schwer zu modellieren sind.


1 Wie alles andere in dieser Antwort ist das eine Verallgemeinerung. Diese Eigenschaft, bei der eine Berechnung ausgewertet wird, wenn ihr Ergebnis benötigt wird, und nicht nacheinander, wo sie aufgerufen wird, wird als "Faulheit" bezeichnet. Nicht alle funktionalen Sprachen sind tatsächlich allgemein faul, noch ist die Faulheit auf funktionale Programmierung beschränkt. Die hier gegebene Beschreibung bietet vielmehr einen „mentalen Rahmen“, um über verschiedene Programmierstile nachzudenken, die keine unterschiedlichen und entgegengesetzten Kategorien sind, sondern fließende Ideen.

Konrad Rudolph
quelle
9
Unsichere Werte wie Benutzereingaben oder Zufallswerte sind in rein funktionalen Sprachen schwer zu modellieren, aber dies ist ein gelöstes Problem. Siehe Monaden.
Apocalisp
" sequentielle Schritte , in denen das Funktionsprogramm verschachtelt wäre" bedeutet, die Trennung von Bedenken durch Hervorheben der Funktionszusammensetzung vorzusehen, dh die Abhängigkeiten zwischen den Teilberechnungen einer deterministischen Berechnung zu trennen.
Shelby Moore III
Dies scheint falsch - Prozeduren können auch verschachtelt sein, Prozeduren können Parameter haben
Hurda
1
@ Hurda Ja, hätte das besser formulieren können. Der Punkt ist, dass die prozedurale Programmierung schrittweise in einer vorgegebenen Reihenfolge erfolgt, während funktionale Programme nicht schrittweise ausgeführt werden. Vielmehr werden Werte berechnet, wenn sie benötigt werden. Das Fehlen einer allgemein vereinbarten Definition der Programmierterminologie macht solche Verallgemeinerungen jedoch nahezu nutzlos. Ich habe meine Antwort in dieser Hinsicht geändert.
Konrad Rudolph
97

Grundsätzlich sind die beiden Stile wie Yin und Yang. Einer ist organisiert, der andere chaotisch. Es gibt Situationen, in denen funktionale Programmierung die offensichtliche Wahl ist, und andere Situationen, in denen prozedurale Programmierung die bessere Wahl ist. Aus diesem Grund gibt es mindestens zwei Sprachen, die kürzlich eine neue Version herausgebracht haben, die beide Programmierstile umfasst. ( Perl 6 und D 2 )

Verfahren:

  • Die Ausgabe einer Routine hat nicht immer eine direkte Korrelation mit der Eingabe.
  • Alles wird in einer bestimmten Reihenfolge erledigt.
  • Die Ausführung einer Routine kann Nebenwirkungen haben.
  • Neigt dazu, die Implementierung von Lösungen auf lineare Weise zu betonen.

Perl 6

sub factorial ( UInt:D $n is copy ) returns UInt {

  # modify "outside" state
  state $call-count++;
  # in this case it is rather pointless as
  # it can't even be accessed from outside

  my $result = 1;

  loop ( ; $n > 0 ; $n-- ){

    $result *= $n;

  }

  return $result;
}

D 2

int factorial( int n ){

  int result = 1;

  for( ; n > 0 ; n-- ){
    result *= n;
  }

  return result;
}

Funktionell:

  • Oft rekursiv.
  • Gibt immer die gleiche Ausgabe für eine bestimmte Eingabe zurück.
  • Die Reihenfolge der Bewertung ist normalerweise undefiniert.
  • Muss staatenlos sein. dh Keine Operation kann Nebenwirkungen haben.
  • Gute Passform für parallele Ausführung
  • Neigt dazu, einen Divide and Conquer-Ansatz zu betonen.
  • Kann die Funktion Lazy Evaluation haben.

Haskell

(kopiert aus Wikipedia );

fac :: Integer -> Integer

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

oder in einer Zeile:

fac n = if n > 0 then n * fac (n-1) else 1

Perl 6

proto sub factorial ( UInt:D $n ) returns UInt {*}

multi sub factorial (  0 ) { 1 }
multi sub factorial ( $n ) { $n * samewith $n-1 } # { $n * factorial $n-1 }

D 2

pure int factorial( invariant int n ){
  if( n <= 1 ){
    return 1;
  }else{
    return n * factorial( n-1 );
  }
}

Randnotiz:

Factorial ist ein gängiges Beispiel, um zu zeigen, wie einfach es ist, neue Operatoren in Perl 6 so zu erstellen, wie Sie eine Unterroutine erstellen würden. Diese Funktion ist in Perl 6 so tief verwurzelt, dass die meisten Operatoren in der Rakudo-Implementierung auf diese Weise definiert werden. Außerdem können Sie vorhandenen Operatoren Ihre eigenen Multi-Kandidaten hinzufügen.

sub postfix:< ! > ( UInt:D $n --> UInt )
  is tighter(&infix:<*>)
  { [*] 2 .. $n }

say 5!; # 120␤

Dieses Beispiel zeigt auch die Bereichserstellung ( 2..$n) und den Meta-Operator zur Listenreduzierung ( [ OPERATOR ] LIST) in Kombination mit dem Multiplikationsoperator für numerische Infixe. ( *)
Es zeigt auch, dass Sie --> UIntdie Signatur anstatt returns UIntdanach eingeben können.

(Sie können mit dem Starten des Bereichs davonkommen, 2da der Multiplikations- "Operator" 1beim Aufruf ohne Argumente zurückkehrt.)

Brad Gilbert
quelle
Hallo, können Sie bitte ein Beispiel für die folgenden 2 Punkte geben, die für "Prozedural" am Beispiel der faktoriellen Implementierung in Perl 6 erwähnt wurden. 1) Die Ausgabe einer Routine hat nicht immer eine direkte Korrelation mit der Eingabe. 2) Die Ausführung einer Routine kann Nebenwirkungen haben.
Naga Kiran
sub postfix:<!> ($n) { [*] 1..$n }
Brad Gilbert
@BradGilbert - No operation can have side effectsKannst du es bitte näher erläutern?
Kushalvm
2
Wahrscheinlich die beste Antwort, die ich jemals finden konnte ... Und ich habe einige Nachforschungen über diese einzelnen Punkte angestellt ... das hat mir wirklich geholfen! :)
Navaneeth
1
@ AkashBisariya sub foo( $a, $b ){ ($a,$b).pick }← gibt nicht immer die gleiche Ausgabe für die gleiche Eingabe zurück, während die folgendensub foo( $a, $b ){ $a + $b }
Brad Gilbert
70

Ich habe diese Definition an keiner anderen Stelle gesehen, aber ich denke, dies fasst die hier angegebenen Unterschiede ziemlich gut zusammen:

Die funktionale Programmierung konzentriert sich auf Ausdrücke

Die prozedurale Programmierung konzentriert sich auf Anweisungen

Ausdrücke haben Werte. Ein Funktionsprogramm ist ein Ausdruck, dessen Wert eine Folge von Anweisungen ist, die der Computer ausführen muss.

Anweisungen haben keine Werte und ändern stattdessen den Status einer konzeptionellen Maschine.

In einer rein funktionalen Sprache würde es keine Anweisungen geben, in dem Sinne, dass es keine Möglichkeit gibt, den Status zu manipulieren (sie könnten immer noch ein syntaktisches Konstrukt namens "Anweisung" haben, aber wenn es den Status nicht manipuliert, würde ich es nicht als Anweisung in diesem Sinne bezeichnen ). In einer rein prozeduralen Sprache würde es keine Ausdrücke geben, alles wäre eine Anweisung, die den Zustand der Maschine manipuliert.

Haskell wäre ein Beispiel für eine rein funktionale Sprache, da es keine Möglichkeit gibt, den Zustand zu manipulieren. Maschinencode wäre ein Beispiel für eine rein prozedurale Sprache, da alles in einem Programm eine Anweisung ist, die den Status der Register und den Speicher der Maschine manipuliert.

Der verwirrende Teil ist, dass die überwiegende Mehrheit der Programmiersprachen sowohl Ausdrücke als auch Anweisungen enthält, sodass Sie Paradigmen mischen können. Sprachen können als funktionaler oder prozeduraler eingestuft werden, je nachdem, wie sehr sie die Verwendung von Anweisungen gegenüber Ausdrücken fördern.

Zum Beispiel wäre C funktionaler als COBOL, da ein Funktionsaufruf ein Ausdruck ist, während das Aufrufen eines Unterprogramms in COBOL eine Anweisung ist (die den Status gemeinsam genutzter Variablen manipuliert und keinen Wert zurückgibt). Python wäre funktionaler als C, da Sie damit bedingte Logik als Ausdruck mithilfe der Kurzschlussauswertung ausdrücken können (test && path1 || path2 im Gegensatz zu if-Anweisungen). Das Schema wäre funktionaler als Python, da alles im Schema ein Ausdruck ist.

Sie können immer noch in einem funktionalen Stil in einer Sprache schreiben, die das prozedurale Paradigma fördert und umgekehrt. Es ist nur schwieriger und / oder umständlicher, in einem Paradigma zu schreiben, das von der Sprache nicht gefördert wird.

Omnimike
quelle
2
Beste und prägnanteste Erklärung, die ich im Internet gesehen habe, Bravo!
tommed
47

In der Informatik ist die funktionale Programmierung ein Programmierparadigma, das die Berechnung als Bewertung mathematischer Funktionen behandelt und Zustands- und veränderbare Daten vermeidet. Es betont die Anwendung von Funktionen im Gegensatz zu dem prozeduralen Programmierstil, der Zustandsänderungen betont.

Juan
quelle
4
Während dies die Erklärung ist, die mir am meisten geholfen hat, bin ich beim Konzept der funktionalen Programmierung immer noch unklar. Ich suche nach einem Programmierstil, der nicht von der Referenzierung externer Objekte abhängt, um ausgeführt zu werden (alles, was die Funktion ausführen muss, sollte als Parameter übergeben werden). Zum Beispiel würde ich niemals GetUserContext()die Funktion eingeben, der Benutzerkontext würde übergeben. Ist das funktionale Programmierung? Danke im Voraus.
Matt Cashatt
26

Ich glaube, dass es bei der prozeduralen / funktionalen / objektiven Programmierung darum geht, wie man ein Problem angeht.

Der erste Stil würde alles in Schritten planen und das Problem lösen, indem jeweils ein Schritt (eine Prozedur) implementiert wird. Andererseits würde die funktionale Programmierung den Divide-and-Conquer-Ansatz hervorheben, bei dem das Problem in ein Unterproblem unterteilt wird, dann jedes Unterproblem gelöst wird (wodurch eine Funktion zur Lösung dieses Unterproblems erstellt wird) und die Ergebnisse kombiniert werden Erstellen Sie die Antwort für das gesamte Problem. Schließlich würde die objektive Programmierung die reale Welt nachahmen, indem eine Mini-Welt im Computer mit vielen Objekten erstellt wird, von denen jedes (etwas) einzigartige Eigenschaften aufweist und mit anderen interagiert. Aus diesen Wechselwirkungen würde das Ergebnis hervorgehen.

Jeder Programmierstil hat seine eigenen Vor- und Nachteile. Daher ist es sehr schwierig, wenn nicht unmöglich, etwas wie "reine Programmierung" zu tun (dh rein prozedural - das tut übrigens niemand, was irgendwie komisch ist - oder rein funktional oder rein objektiv), mit Ausnahme einiger elementarer Probleme entwickelt, um den Vorteil eines Programmierstils zu demonstrieren (daher nennen wir diejenigen, die Reinheit mögen, "weenie": D).

Aus diesen Stilen haben wir dann Programmiersprachen, die für jeden Stil optimiert sind. Bei der Versammlung dreht sich beispielsweise alles um Verfahren. Okay, die meisten frühen Sprachen sind prozedural, nicht nur Asm, wie C, Pascal (und Fortran, wie ich gehört habe). Dann haben wir alle berühmtes Java in der objektiven Schule (Java und C # gehören eigentlich auch zu einer Klasse namens "geldorientiert", aber das ist Gegenstand einer weiteren Diskussion). Ebenfalls objektiv ist Smalltalk. In der funktionalen Schule hätten wir "fast funktionale" (einige hielten sie für unrein) Lisp-Familie und ML-Familie und viele "rein funktionale" Haskell, Erlang usw. Übrigens gibt es viele allgemeine Sprachen wie Perl, Python , Ruby.

Aaron Hall
quelle
26

Funktionsprogrammierung

num = 1 
def function_to_add_one(num):
    num += 1
    return num


function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)

#Final Output: 2

Verfahrensprogrammierung

num = 1 
def procedure_to_add_one():
    global num
    num += 1
    return num


procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()

#Final Output: 6

function_to_add_one ist eine Funktion

procedure_to_add_one ist eine Prozedur

Selbst wenn Sie die Funktion fünfmal ausführen , wird jedes Mal 2 zurückgegeben

Wenn Sie die Prozedur fünfmal ausführen , erhalten Sie am Ende des fünften Durchlaufs 6 .

Hamza Zubair
quelle
5
Dieses Beispiel ist wirklich einfach zu verstehen, der Begriff "zustandslose" und "unveränderliche Daten" in der funktionalen Programmierung. Das Lesen aller oben aufgeführten Definitionen und Unterschiede hat meine Verwirrung erst durch das Lesen dieser Antwort beseitigt. Danke dir!
Maximus
13

Um Konrads Kommentar zu erweitern:

Infolgedessen liefert ein rein funktionales Programm immer den gleichen Wert für eine Eingabe, und die Reihenfolge der Auswertung ist nicht genau definiert.

Aus diesem Grund ist Funktionscode im Allgemeinen einfacher zu parallelisieren. Da es (im Allgemeinen) keine Nebenwirkungen der Funktionen gibt und sie (im Allgemeinen) nur auf ihre Argumente reagieren, verschwinden viele Parallelitätsprobleme.

Funktionale Programmierung wird auch verwendet, wenn Sie in der Lage sein müssen, zu beweisen Ihr Code korrekt ist. Dies ist bei der prozeduralen Programmierung viel schwieriger (nicht einfach mit funktionalen, aber immer noch einfacher).

Haftungsausschluss: Ich habe seit Jahren keine funktionale Programmierung mehr verwendet und erst vor kurzem wieder angefangen, sie zu betrachten, sodass ich hier möglicherweise nicht ganz richtig bin. :) :)

Herms
quelle
12

Eine Sache, die ich hier nicht wirklich betont hatte, ist, dass moderne Funktionssprachen wie Haskell mehr auf erstklassigen Funktionen zur Flusskontrolle als auf expliziter Rekursion basieren. Sie müssen in Haskell keine faktorielle rekursive Definition vornehmen, wie oben beschrieben. Ich denke so etwas

fac n = foldr (*) 1 [1..n]

ist eine vollkommen idiomatische Konstruktion und im Geiste der Verwendung einer Schleife viel näher als der Verwendung einer expliziten Rekursion.

C Hogg
quelle
10

Eine funktionale Programmierung ist identisch mit einer prozeduralen Programmierung, bei der keine globalen Variablen verwendet werden.

Nir O.
quelle
7

Prozedurale Sprachen neigen dazu, den Status zu verfolgen (unter Verwendung von Variablen) und werden in der Regel als Folge von Schritten ausgeführt. Rein funktionale Sprachen verfolgen den Status nicht, verwenden unveränderliche Werte und werden in der Regel als eine Reihe von Abhängigkeiten ausgeführt. In vielen Fällen enthält der Status des Aufrufstapels die Informationen, die denen entsprechen, die in Statusvariablen im Prozedurcode gespeichert sind.

Rekursion ist ein klassisches Beispiel für funktionale Programmierung.

Keil
quelle
1
Nachdem ich diese Seite gelesen hatte, dachte ich an dasselbe -> "Rekursion ist ein klassisches Beispiel für funktionale Stilprogrammierung", und Sie haben es gelöscht. Danke, jetzt denke ich, dass ich etwas bekomme.
Mudassir Hussain
6

Konrad sagte:

Infolgedessen liefert ein rein funktionales Programm immer den gleichen Wert für eine Eingabe, und die Reihenfolge der Auswertung ist nicht genau definiert. Dies bedeutet, dass unsichere Werte wie Benutzereingaben oder Zufallswerte in rein funktionalen Sprachen schwer zu modellieren sind.

Die Reihenfolge der Auswertung in einem rein funktionalen Programm mag schwer (ähm) zu begründen sein (insbesondere mit Faulheit) oder sogar unwichtig, aber ich denke, wenn man sagt, dass es nicht genau definiert ist, hört es sich so an, als könne man nicht sagen, ob Ihr Programm läuft überhaupt arbeiten!

Eine bessere Erklärung wäre vielleicht, dass der Kontrollfluss in Funktionsprogrammen davon abhängt, wann der Wert der Argumente einer Funktion benötigt wird. Das Gute daran ist, dass in gut geschriebenen Programmen der Status explizit wird: Jede Funktion listet ihre Eingaben als Parameter auf, anstatt den globalen Status willkürlich zu ändern . Auf einer bestimmten Ebene ist es daher einfacher, die Reihenfolge der Bewertung in Bezug auf jeweils eine Funktion zu bestimmen . Jede Funktion kann den Rest des Universums ignorieren und sich auf das konzentrieren, was sie tun muss. In Kombination funktionieren Funktionen garantiert genauso [1] wie isoliert.

... unsichere Werte wie Benutzereingaben oder Zufallswerte sind in rein funktionalen Sprachen schwer zu modellieren.

Die Lösung für das Eingabeproblem in rein funktionalen Programmen besteht darin, eine imperative Sprache als DSL unter Verwendung einer ausreichend leistungsfähigen Abstraktion einzubetten . In imperativen (oder nicht reinen funktionalen) Sprachen ist dies nicht erforderlich, da Sie den Status implizit "betrügen" und übergeben können und die Reihenfolge der Bewertung explizit ist (ob Sie es mögen oder nicht). Aufgrund dieses "Betrugs" und der erzwungenen Auswertung aller Parameter für jede Funktion verlieren Sie in wichtigen Sprachen 1) die Fähigkeit, eigene Kontrollflussmechanismen (ohne Makros) zu erstellen, 2) Code ist nicht von Natur aus threadsicher und / oder parallelisierbar standardmäßig, 3) und das Implementieren von etwas wie Rückgängig (Zeitreise) erfordert sorgfältige Arbeit (ein zwingender Programmierer muss ein Rezept speichern, um die alten Werte zurückzubekommen!), Während reine funktionale Programmierung Ihnen all diese Dinge kauft - und ein paar mehr kann ich vergessen haben - "kostenlos".

Ich hoffe, das klingt nicht nach Eifer, ich wollte nur eine Perspektive hinzufügen. Imperative Programmierung und insbesondere gemischte Paradigmenprogrammierung in leistungsstarken Sprachen wie C # 3.0 sind immer noch absolut effektive Methoden, um Dinge zu erledigen, und es gibt keine Silberkugel .

[1] ... außer möglicherweise in Bezug auf die Speichernutzung (vgl. Foldl und foldl 'in Haskell).

Jared Updike
quelle
5

Um Konrads Kommentar zu erweitern:

und die Reihenfolge der Bewertung ist nicht genau definiert

Einige funktionale Sprachen haben eine sogenannte Lazy Evaluation. Dies bedeutet, dass eine Funktion erst ausgeführt wird, wenn der Wert benötigt wird. Bis zu diesem Zeitpunkt wird die Funktion selbst weitergegeben.

Prozedurale Sprachen sind Schritt 1, Schritt 2, Schritt 3 ... Wenn Sie in Schritt 2 sagen, dass Sie 2 + 2 hinzufügen, macht es das richtig. In der verzögerten Auswertung würde man sagen, addiere 2 + 2, aber wenn das Ergebnis nie verwendet wird, wird es niemals addiert.

Brian Leahy
quelle
4

Wenn Sie eine Chance haben, würde ich empfehlen, eine Kopie von Lisp / Scheme zu erhalten und einige Projekte darin durchzuführen. Die meisten Ideen, die in letzter Zeit zu Bandwaggons geworden sind, wurden vor Jahrzehnten in Lisp zum Ausdruck gebracht: funktionale Programmierung, Fortsetzungen (als Abschlüsse), Speicherbereinigung, sogar XML.

Das wäre also ein guter Weg, um sich einen Vorsprung bei all diesen aktuellen Ideen zu verschaffen, und noch ein paar mehr, wie zum Beispiel die symbolische Berechnung.

Sie sollten wissen, wofür funktionale Programmierung gut ist und wofür sie nicht gut ist. Es ist nicht für alles gut. Einige Probleme lassen sich am besten in Form von Nebenwirkungen ausdrücken, bei denen dieselbe Frage je nach Zeitpunkt der Beantwortung unterschiedliche Antworten gibt.

Mike Dunlavey
quelle
3

@Creighton:

In Haskell gibt es eine Bibliotheksfunktion namens product :

prouduct list = foldr 1 (*) list

oder einfach:

product = foldr 1 (*)

also die "idiomatische" Fakultät

fac n = foldr 1 (*)  [1..n]

wäre einfach

fac n = product [1..n]
Jared Updike
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klarstellung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
Nick Kitto
Ich glaube, dies wurde vor vielen Jahren gepostet, bevor das Kommentarsystem hinzugefügt wurde, wenn Sie es glauben können: stackoverflow.com/help/badges/30/beta?userid=2543
Jared Updike
2

Die prozedurale Programmierung unterteilt Sequenzen von Anweisungen und bedingten Konstrukten in separate Blöcke, die als Prozeduren bezeichnet werden und über Argumente parametrisiert werden, die (nicht funktionale) Werte sind.

Die funktionale Programmierung ist dieselbe, außer dass Funktionen erstklassige Werte sind, sodass sie als Argumente an andere Funktionen übergeben und als Ergebnis von Funktionsaufrufen zurückgegeben werden können.

Beachten Sie, dass die funktionale Programmierung eine Verallgemeinerung der prozeduralen Programmierung in dieser Interpretation ist. Eine Minderheit interpretiert "funktionale Programmierung" jedoch als nebenwirkungsfrei, was sehr unterschiedlich, aber für alle wichtigen funktionalen Sprachen außer Haskell irrelevant ist.

Jon Harrop
quelle
1

Um den Unterschied zu verstehen, muss man verstehen, dass das "Paten" -Paradigma sowohl der prozeduralen als auch der funktionalen Programmierung die zwingende Programmierung ist .

Grundsätzlich ist die prozedurale Programmierung lediglich eine Möglichkeit, imperative Programme zu strukturieren, bei denen die primäre Abstraktionsmethode die "Prozedur" ist. (oder "Funktion" in einigen Programmiersprachen). Sogar die objektorientierte Programmierung ist nur eine andere Möglichkeit, ein imperatives Programm zu strukturieren, bei dem der Status in Objekten eingekapselt ist und zu einem Objekt mit einem "aktuellen Status" wird. Außerdem verfügt dieses Objekt über eine Reihe von Funktionen, Methoden und anderen Dingen, mit denen Sie das tun können Programmierer manipulieren oder aktualisieren den Status.

In Bezug auf die funktionale Programmierung besteht der Kern seines Ansatzes darin, zu identifizieren, welche Werte zu nehmen sind und wie diese Werte übertragen werden sollen. (Es gibt also keinen Status und keine veränderlichen Daten, da Funktionen als erstklassige Werte verwendet und als Parameter an andere Funktionen übergeben werden.)

PS: Das Verständnis jedes Programmierparadigmas sollte die Unterschiede zwischen allen klären.

PSS: Letztendlich sind Programmierparadigmen nur verschiedene Ansätze zur Lösung von Problemen.

PSS: Diese Quora-Antwort hat eine großartige Erklärung.

Fouad Boukredine
quelle
0

Keine der Antworten hier zeigt eine idiomatische funktionale Programmierung. Die rekursive faktorielle Antwort eignet sich hervorragend zur Darstellung der Rekursion in FP, aber der Großteil des Codes ist nicht rekursiv, sodass ich nicht denke, dass die Antwort vollständig repräsentativ ist.

Angenommen, Sie haben ein Array von Zeichenfolgen, und jede Zeichenfolge repräsentiert eine Ganzzahl wie "5" oder "-200". Sie möchten dieses Eingabe-Array von Zeichenfolgen mit Ihrem internen Testfall vergleichen (Verwenden eines Ganzzahlvergleichs). Beide Lösungen sind unten gezeigt

Verfahren

arr_equal(a : [Int], b : [Str]) -> Bool {
    if(a.len != b.len) {
        return false;
    }

    bool ret = true;
    for( int i = 0; i < a.len /* Optimized with && ret*/; i++ ) {
        int a_int = a[i];
        int b_int = parseInt(b[i]);
        ret &= a_int == b_int;  
    }
    return ret;
}

Funktionell

eq = i, j => i == j # This is usually a built-in
toInt = i => parseInt(i) # Of course, parseInt === toInt here, but this is for visualization

arr_equal(a : [Int], b : [Str]) -> Bool =
    zip(a, b.map(toInt)) # Combines into [Int, Int]
   .map(eq)
   .reduce(true, (i, j) => i && j) # Start with true, and continuously && it with each value

Während reine funktionale Sprachen im Allgemeinen Forschungssprachen sind (da die reale Welt freie Nebenwirkungen mag), verwenden reale prozedurale Sprachen bei Bedarf die viel einfachere funktionale Syntax.

Dies wird normalerweise mit einer externen Bibliothek wie Lodash implementiert oder ist in neueren Sprachen wie Rust integriert . Das Heben schwerer Lasten der funktionalen Programmierung mit Funktionen / Konzepte gemacht wie map, filter, reduce, currying, partial, die letzten drei , von denen Sie für das weitere Verständnis nachschlagen kann.

Nachtrag

Um in freier Wildbahn verwendet zu werden, muss der Compiler normalerweise herausfinden, wie die Funktionsversion intern in die prozedurale Version konvertiert wird, da der Overhead für Funktionsaufrufe zu hoch ist. Rekursive Fälle wie die gezeigte Fakultät verwenden Tricks wie Tail Call , um die Verwendung von O (n) -Speicher zu entfernen. Die Tatsache, dass es keine Nebenwirkungen gibt, ermöglicht es funktionalen Compilern, die && retOptimierung auch dann zu implementieren , wenn .reducedies zuletzt durchgeführt wurde. Die Verwendung von Lodash in JS ermöglicht offensichtlich keine Optimierung, sodass die Leistung beeinträchtigt wird (was bei der Webentwicklung normalerweise kein Problem darstellt). Sprachen wie Rust werden intern optimiert (und verfügen über Funktionen try_foldzur Unterstützung der && retOptimierung).

Nicholas Pipitone
quelle