Warum ist Python nicht sehr gut für die funktionale Programmierung? [geschlossen]

324

Ich habe immer gedacht, dass funktionale Programmierung in Python möglich ist. Daher war ich überrascht, dass Python in dieser Frage nicht viel erwähnt wurde , und als es erwähnt wurde, war es normalerweise nicht sehr positiv. Hierfür wurden jedoch nicht viele Gründe angegeben (fehlende Musterübereinstimmung und algebraische Datentypen wurden erwähnt). Meine Frage ist also: Warum ist Python nicht sehr gut für die funktionale Programmierung? Gibt es mehr Gründe als das Fehlen von Mustervergleich und algebraischen Datentypen? Oder sind diese Konzepte für die funktionale Programmierung so wichtig, dass eine Sprache, die sie nicht unterstützt, nur als zweitklassige funktionale Programmiersprache eingestuft werden kann? (Denken Sie daran, dass meine Erfahrung mit funktionaler Programmierung sehr begrenzt ist.)

David Johnstone
quelle
2
2018 - Coconut (eine funktionale Programmiersprache, die zu Python kompiliert wird) verbessert die funktionale Programmierung in Python. Siehe auch diese Artikelserie von IBM Seite 1 Seite
Cssyphus

Antworten:

393

Bei der Frage, auf die Sie sich beziehen, wird gefragt, welche Sprachen sowohl die OO- als auch die funktionale Programmierung fördern. Python fördert keine funktionale Programmierung, obwohl es ziemlich gut funktioniert .

Das beste Argument gegen die funktionale Programmierung in Python ist, dass imperative / OO-Anwendungsfälle von Guido sorgfältig geprüft werden, während dies bei funktionalen Programmieranwendungsfällen nicht der Fall ist. Wenn ich imperatives Python schreibe, ist es eine der schönsten Sprachen, die ich kenne. Wenn ich funktionales Python schreibe, wird es so hässlich und unangenehm wie Ihre durchschnittliche Sprache ohne BDFL .

Das heißt nicht, dass es schlecht ist, nur dass Sie härter arbeiten müssen als wenn Sie zu einer Sprache wechseln würden, die die funktionale Programmierung fördert, oder zum Schreiben von OO Python.

Hier sind die funktionalen Dinge, die ich in Python vermisse:


  • Kein Mustervergleich und keine Schwanzrekursion bedeuten, dass Ihre grundlegenden Algorithmen unbedingt geschrieben werden müssen. Die Rekursion ist in Python hässlich und langsam.
  • Eine kleine Listenbibliothek und keine funktionalen Wörterbücher bedeuten, dass Sie selbst viel schreiben müssen.
  • Keine Syntax für Currying oder Komposition bedeutet, dass der punktfreie Stil ungefähr so ​​punktuell ist wie das explizite Übergeben von Argumenten.
  • Iteratoren anstelle von faulen Listen bedeuten, dass Sie wissen müssen, ob Sie Effizienz oder Persistenz wünschen, und Anrufe an die listUmgebung verteilen müssen, wenn Sie Persistenz wünschen. (Iteratoren werden einmal verwendet)
  • Die einfache imperative Syntax von Python und der einfache LL1-Parser bedeuten, dass eine bessere Syntax für if-Ausdrücke und Lambda-Ausdrücke grundsätzlich unmöglich ist. Guido mag es so und ich denke er hat recht.
Nathan Shively-Sanders
quelle
5
+1 für fehlende Schwanzrekursion - obwohl Schleifenkonstrukte sie abgelöst haben, ist es immer noch etwas wert, zwischen Python und Schema zu fehlen.
new123456
5
Hervorragende Antwort hinsichtlich Vollständigkeit und Zusammensetzung. Leider hat es, wie bei so vielen Antworten mit einem starken funktionalen Hintergrund, eine missbräuchliche Verwendung der Terminologie durch IMO. Obwohl ich verstehe, dass Sie nicht jedes Konzept in einer Antwort näher erläutern können, frage ich mich, ob das OP (mit zugegebenermaßen eingeschränktem FP-Hintergrund) gut informiert ist, wenn Sie Begriffe wie "Mustervergleich", "Funktionswörterbücher", "Currying" oder "Currying" lesen. faule Listen ".
ThomasH
4
Guter Punkt; Ich denke, die Lösung besteht darin, Links hinzuzufügen. Haben Sie genug Mitarbeiter, um meine Antwort zu bearbeiten? In diesem Fall können Sie Links zu den verschiedenen Konzepten hinzufügen. Ich werde anfangen, wenn ich später Zeit habe.
Nathan Shively-Sanders
5
Mir ist klar, dass dies 5 Jahre alt ist, aber… es scheint mehr um die Dinge zu gehen, die Sie in Haskell vermissen , nicht um funktionale Sprachen . Zum Beispiel haben die meisten ML- und Lisp-Dialekte und Nachkommen kein automatisches Currying, machen den punktfreien Stil zu ausführlich, haben keine faulen Listen usw. Wenn also Iteratoren anstelle von faulen Listen Python zu einer schlechten funktionalen Sprache machen, haben Auch darf CaML keine schreckliche funktionale Sprache sein?
abarnert
4
@abarnert: Caml hat jeden Aufzählungspunkt außer Lazy Lists, die als Bibliothek verfügbar sind. Ich habe gelegentlich Caml verwendet, als ich diese Antwort geschrieben habe, und verwende derzeit F #. Sie sind beide sehr schöne funktionale Sprachen.
Nathan Shively-Sanders
102

Guido hat eine gute Erklärung dafür hier . Hier ist der relevanteste Teil:

Ich habe nie gedacht, dass Python stark von funktionalen Sprachen beeinflusst wird, egal was die Leute sagen oder denken. Ich war mit imperativen Sprachen wie C und Algol 68 viel besser vertraut, und obwohl ich Funktionen erstklassiger Objekte erstellt hatte, sah ich Python nicht als funktionale Programmiersprache an. Zuvor war jedoch klar, dass Benutzer viel mehr mit Listen und Funktionen tun wollten.

...

Es ist auch erwähnenswert, dass die Einführung von Verschlüssen bei der Entwicklung vieler anderer erweiterter Programmierfunktionen hilfreich war, obwohl ich mir Python nicht als funktionale Sprache vorgestellt habe. Beispielsweise hängen bestimmte Aspekte von Klassen neuen Stils, Dekorateuren und anderen modernen Merkmalen von dieser Fähigkeit ab.

Obwohl im Laufe der Jahre eine Reihe von funktionalen Programmierfunktionen eingeführt wurden, fehlen Python immer noch bestimmte Funktionen, die in „echten“ funktionalen Programmiersprachen zu finden sind. Beispielsweise führt Python bestimmte Arten von Optimierungen nicht durch (z. B. Schwanzrekursion). Im Allgemeinen ist es aufgrund der extrem dynamischen Natur von Python unmöglich, die aus funktionalen Sprachen wie Haskell oder ML bekannte Art der Optimierung der Kompilierungszeit durchzuführen. Und das ist gut so.

Ich ziehe zwei Dinge heraus:

  1. Der Schöpfer der Sprache betrachtet Python nicht wirklich als funktionale Sprache. Daher ist es möglich, "funktionale" Funktionen zu sehen, aber es ist unwahrscheinlich, dass Sie etwas sehen, das definitiv funktional ist.
  2. Die Dynamik von Python verhindert einige der Optimierungen, die Sie in anderen funktionalen Sprachen sehen. Zugegeben, Lisp ist genauso dynamisch (wenn nicht dynamischer) wie Python, daher ist dies nur eine teilweise Erklärung.
Jason Baker
quelle
8
Sie können die Tail-Call-Optimierung in Python problemlos durchführen. Guido hat das nicht verstanden.
Jules
26
Es scheint darauf hinauszulaufen , dass Guido van Rossum keinen funktionalen Stil mag .
Svante
59
Ich denke, es ist genauer zu sagen, dass Guido van Rossum den funktionalen Stil nicht versteht und nicht versteht, warum Python sie braucht. Sie müssen zwei Dinge verstehen: 1) Programmiersprachen befinden sich am Ende eines Technologie-Stacks und wirken sich auf alles aus, was darauf aufbaut, und 2) wie bei jeder anderen Software ist es einfacher, Funktionen hinzuzufügen, als sie zu entfernen. Ich denke, es ist eine gute Qualität für einen Sprachdesigner, diese Art von Anfragen zu kritisieren.
Jason Baker
8
"Zugegeben, Lisp ist genauso dynamisch" -> und genauso wichtig!
Pyon
6
@Jules, macht es Ihnen etwas aus, eine Richtlinie für die Verwendung der Tail-Call-Optimierung in Python zu teilen? Ein Zeiger auf eine Quelle wäre nützlich.
David Shaked
52

Das Schema hat keine algebraischen Datentypen oder Mustervergleiche, aber es ist sicherlich eine funktionale Sprache. Ärgerliche Dinge über Python aus Sicht der funktionalen Programmierung:

  1. Verkrüppelte Lambdas. Da Lambdas nur einen Ausdruck enthalten kann und Sie in einem Ausdruckskontext nicht alles so einfach ausführen können, sind die Funktionen, die Sie "on the fly" definieren können, begrenzt.

  2. Ifs sind Anweisungen, keine Ausdrücke. Dies bedeutet unter anderem, dass Sie kein Lambda mit einem If darin haben können. (Dies wird durch Ternaries in Python 2.5 behoben, sieht aber hässlich aus.)

  3. Guido droht Karte, Filter zu entfernen, und reduzieren jeder einmal in eine Weile

Auf der anderen Seite hat Python lexikalische Verschlüsse, Lambdas und Listenverständnisse (die wirklich ein "funktionales" Konzept sind, unabhängig davon, ob Guido es zugibt oder nicht). Ich programmiere viel in Python im "funktionalen Stil", aber ich würde kaum sagen, dass es ideal ist.

Jacob B.
quelle
3
Map, Filter und Reduce werden in Python wirklich nicht benötigt. Ich habe noch keinen Code gesehen, der durch die Verwendung stark vereinfacht wurde. Außerdem kann das Aufrufen von Funktionen in Python teuer sein. Daher ist es normalerweise besser, nur ein Listen- / Generatorverständnis oder eine for-Schleife zu verwenden.
Jason Baker
2
Dies ist genau das, was Nathan Sanders unten sagt: "Python fördert keine funktionale Programmierung, obwohl es ziemlich gut funktioniert." Wenn Guido wollte, dass Python eine funktionale Sprache wird, würde er dafür sorgen, dass die Implementierung gut genug funktioniert, um Wegwerffunktionen zu verwenden, und Lambdas so weit entkrüppeln, dass Sie Map / Filter / Reduce tatsächlich auf nützliche Weise verwenden können. Auf der anderen Seite beginnen funktionale Menschen, sich der Großartigkeit des Listenverständnisses bewusst zu werden. Hoffentlich müssen wir nicht den einen oder anderen auswählen.
Jacob B
7
Karte und Filter werden trivial durch ein Listenverständnis ersetzt. reduzieren - fast immer - es so ineffizient, dass es durch eine Generatorfunktion ersetzt werden sollte.
S.Lott
13
@ S.Lott wie ersetzt man Reduzieren durch einen Generator?
Antimon
17
Das Verständnis der @ JacobB-Liste war etwa 15 Jahre vor der Erfindung von Python und 25 Jahre vor der Implementierung der Funktion durch Python in funktionalen Sprachen verfügbar. Die Idee, dass Python ihre Verbreitung beeinflusst hat oder dass fp dies von Python gelernt hat oder einfach nur, dass es in der fp-Welt nach der Python-Implementierung populär ist, ist einfach falsch. Die Implementierung von Python wurde direkt von Haskell übernommen. Vielleicht habe ich Sie falsch verstanden , und das ist nicht das, was Sie wollen, aber ich bin verwirrt von „functional Menschen beginnen mit dem awesomeness Listenkomprehensionen aufzuwachen“.
Itsbruce
23

Ich würde Python niemals als "funktional" bezeichnen, aber wenn ich in Python programmiere, ist der Code immer fast rein funktional.

Zugegeben, das liegt hauptsächlich am sehr guten Listenverständnis. Daher würde ich Python nicht unbedingt als funktionale Programmiersprache vorschlagen, aber ich würde jedem, der Python verwendet, funktionale Programmierung vorschlagen.

Konrad Rudolph
quelle
17

Lassen Sie mich mit einem Code demonstrieren, der aus einer Antwort auf eine "funktionale" Python-Frage zu SO stammt

Python:

def grandKids(generation, kidsFunc, val):
  layer = [val]
  for i in xrange(generation):
    layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
  return layer

Haskell:

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation

Der wesentliche Unterschied ist hier, dass Haskell Standard - Bibliothek nützliche Funktionen für funktionale Programmierung hat: in diesem Fall iterate, concatund(!!)

Yairchu
quelle
7
Hier ist ein einzeiliger Ersatz für grandKids()body mit Generatorausdrücken : return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val]).
Lloeki
6
Und hier ist eine, die auch nicht benötigt concat:return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])
Lloeki
9
@Lloeki: Iteration würde diesen Code erheblich vereinfachen, und (x für v in a für x in kidsFunc (v)) ist viel klarer als concatMap (kidsFunc). Pythons Mangel an netten Buildins höherer Ordnung macht äquivalenten Code im Vergleich zu Haskell kryptisch und ausführlich.
Phob
2
concat kann ersetzt werden durchitertools.chain.from_iterable
Antimon
@ Antimon: gut zu wissen. thx
yairchu
14

Eine Sache, die für diese Frage (und die Antworten) wirklich wichtig ist, ist die folgende: Was zum Teufel ist funktionale Programmierung und was sind die wichtigsten Eigenschaften davon. Ich werde versuchen, meine Meinung dazu zu äußern:

Funktionale Programmierung ähnelt dem Schreiben von Mathematik auf einem Whiteboard. Wenn Sie Gleichungen auf ein Whiteboard schreiben, denken Sie nicht an eine Ausführungsreihenfolge. Es gibt (typischerweise) keine Mutation. Sie kommen am nächsten Tag nicht zurück und sehen es sich an, und wenn Sie die Berechnungen erneut durchführen, erhalten Sie ein anderes Ergebnis (oder Sie können, wenn Sie frischen Kaffee getrunken haben :)). Grundsätzlich ist das, was auf der Tafel steht, da, und die Antwort war bereits da, als Sie anfingen, Dinge aufzuschreiben. Sie haben einfach noch nicht bemerkt, was es ist.

Funktionale Programmierung ist sehr ähnlich; Sie ändern nichts, Sie bewerten nur die Gleichung (oder in diesem Fall "Programm") und finden heraus, wie die Antwort lautet. Das Programm ist immer noch da, unverändert. Das gleiche gilt für die Daten.

Ich würde Folgendes als die wichtigsten Merkmale der funktionalen Programmierung einstufen: a) referenzielle Transparenz - Wenn Sie dieselbe Aussage zu einem anderen Zeitpunkt und an einem anderen Ort bewerten, aber mit denselben variablen Werten, bedeutet dies immer noch dasselbe. b) Keine Nebenwirkung - egal wie lange Sie auf das Whiteboard starren, die Gleichung, die ein anderer Mann auf ein anderes Whiteboard schaut, ändert sich nicht versehentlich. c) Funktionen sind ebenfalls Werte. die herumgereicht und mit oder auf andere Variablen angewendet werden können. d) Funktionszusammensetzung, Sie können h = g · f ausführen und somit eine neue Funktion h (..) definieren, die dem Aufruf von g (f (..)) entspricht.

Diese Liste befindet sich in meiner priorisierten Reihenfolge, daher ist referenzielle Transparenz am wichtigsten, gefolgt von keinen Nebenwirkungen.

Wenn Sie nun Python durchgehen und prüfen, wie gut die Sprache und die Bibliotheken diese Aspekte unterstützen und garantieren, sind Sie auf dem besten Weg, Ihre eigene Frage zu beantworten.

Xeno
quelle
2
Funktionen sind in Python erstklassig.
Carl Smith
@CarlSmith Das, aber lässt 3/4, das Python nicht hat. : - \
Arya
1
Ich denke nicht, dass Python eine gute Sprache für die funktionale Programmierung ist. Ich bin mir jetzt nicht mal sicher, was ich mit diesem Kommentar gemeint habe, um ehrlich zu sein. Es scheint für die Antwort nicht relevant zu sein. Ich würde es löschen, aber dann wäre Ihr Kommentar aus dem Zusammenhang geraten.
Carl Smith
1
Referenzielle Transparenz und Unveränderlichkeit sind keine wirklichen Sprachmerkmale. Ja, einige Sprachen (Haskell) betonen sie und machen es schwierig, sie nicht zu haben, aber Sie können eine referenziell transparente Funktion oder ein unveränderliches Objekt in praktisch jeder Sprache erstellen. Sie müssen nur die Standardbibliothek umgehen, die sie häufig verletzt.
Kevin
Python unterstützt sowohl Currying als auch Komposition, jedoch nicht auf Sprachebene, sondern in der Standardbibliothek.
Kevin
10

Python ist fast eine funktionale Sprache. Es ist "funktionale Lite".

Es hat zusätzliche Funktionen, so dass es für einige nicht rein genug ist.

Es fehlen auch einige Funktionen, so dass es für einige nicht vollständig genug ist.

Die fehlenden Funktionen sind relativ einfach zu schreiben. Schauen Sie sich Beiträge wie diese auf FP in Python.

S.Lott
quelle
2
Zum größten Teil stimme ich diesem Beitrag zu. Aber ich kann nicht zustimmen, dass Python eine funktionale Sprache ist. Es fördert die zwingende Programmierung sehr und es ist schwierig, die von Ihnen erwähnten "zusätzlichen Funktionen" nicht zu verwenden. Ich denke, es ist am besten, Python als "funktionale Lite" zu bezeichnen, wie Sie es in dem anderen Beitrag getan haben. :-)
Jason Baker
8
-1 Entschuldigung, nein. Ich meine nur nein. Funktionale Sprachen bieten Konstrukte, die das formale Denken erleichtern: induktiv (ML), äquational (Haskell). Verschlüsse und anonyme Funktionen allein sind nur syntaktischer Zucker für das Strategiemuster.
Pyon
8

Ein weiterer Grund, der oben nicht erwähnt wurde, ist, dass viele integrierte Funktionen und Methoden von integrierten Typen ein Objekt ändern, das geänderte Objekt jedoch nicht zurückgeben. Wenn diese geänderten Objekte zurückgegeben würden, würde dies den Funktionscode sauberer und prägnanter machen. Wenn beispielsweise some_list.append (some_object) some_list mit angehängtem some_object zurückgegeben hat.

DVD Avins
quelle
4

Neben anderen Antworten ist ein Grund dafür, dass Python und die meisten anderen Multi-Paradigmen-Sprachen für eine echte funktionale Programmierung nicht gut geeignet sind, dass ihre Compiler / virtuellen Maschinen / Laufzeiten keine funktionale Optimierung unterstützen. Diese Art der Optimierung wird erreicht, indem der Compiler die mathematischen Regeln versteht. Beispielsweise unterstützen viele Programmiersprachen amap Funktion oder Methode. Dies ist eine ziemlich Standardfunktion, die eine Funktion als ein Argument und eine iterable als zweites Argument verwendet und diese Funktion dann auf jedes Element in der iterable anwendet.

Wie auch immer, es stellt sich heraus, dass map( foo() , x ) * map( foo(), y )es dasselbe ist wiemap( foo(), x * y ) . Der letztere Fall ist tatsächlich schneller als der erstere, da der erstere zwei Kopien ausführt, während der letztere eine ausführt.

Bessere Funktionssprachen erkennen diese mathematisch basierten Beziehungen und führen die Optimierung automatisch durch. Sprachen, die nicht dem Funktionsparadigma gewidmet sind, werden wahrscheinlich nicht optimiert.


quelle
map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )gilt nicht für alle Funktionen. Betrachten Sie beispielsweise den Fall bei der fooBerechnung einer Ableitung.
Eli Korvigo
1
Ich denke er meinte +statt *.
user1747134
Sie nehmen an, dass foo () linear ist?
Juan Isaza
Diese Eigenschaft gilt NICHT für foo (x) = x + 1. As (x + 1) * (y + 1)! = X * y + 1.
Juan Isaza