Ich bin daran interessiert, funktionale Programmierung besser zu lernen. Es liegt auf der Hand, dass ich mich dazu zwingen sollte, eine möglichst reine funktionale Programmiersprache zu verwenden. Daher bitte ich hier mehr oder weniger darum, funktionale Programmiersprachen nach ihrer Reinheit zu ordnen.
Es scheint mir, dass es praktischer wäre, Lisp oder Clojure (oder Scheme oder Scala usw.) zu lernen, aber was ich kürzlich gehört habe, ist es sehr schwer, Haskell zu schlagen, wenn er jemandem Prinzipien der funktionalen Programmierung beibringt. Da ich mir noch nicht sicher bin, frage ich Sie: Welche ist die reinste funktionale Programmiersprache? Eine Bestellung wäre toll, wenn mehrere um den großartigen Titel der reinsten funktionalen Programmiersprache konkurrieren.
Antworten:
Es gibt keine Skala für die Beurteilung des Reinheitsgrades von funktionalen Sprachen. Wenn die Sprache Nebenwirkungen zulässt, ist sie unrein, ansonsten ist sie rein. Nach dieser Definition sind Haskell, Mercury, Clean usw. reine Funktionssprachen. wohingegen Scala, Clojure, F #, OCaml usw. unreine sind.
EDIT: Vielleicht hätte ich sagen sollen: "Wenn die Sprache keine Nebenwirkungen zulässt, ohne das Typensystem zu informieren , ist sie rein. Sonst ist sie unrein."
quelle
IO
Monade). Es ist nur so, dass Code, der Nebenwirkungen verursacht, eindeutig als solcher gekennzeichnet ist. Ich denke nicht, dass es nützlich ist, von reinen / unreinen Sprachen zu sprechen (Haskell lässt Sie zwingend programmieren! Keuchen!), Aber es kann trotzdem nützlich sein, von Codestücken (Funktion, Modul, Programm, was auch immer) als rein zu sprechen /unrein.IO
Monade ist rein. Es ist die Laufzeitbibliothek, die nicht Ihr Code ist, da Ihremain
Funktion im Grunde ein riesiger Zustandstransformator ist. (Etwas wiemain :: World -> World
hinter den Kulissen)program = "some C code"
, und dann kümmert sich die Laufzeitumgebung um den C-Code. :-)Da Lernen Ihr Ziel ist und Sie keine Programme an sich schreiben , können Sie nichts Reineres als Lambda Calculus erreichen .
Lambda Calculus gab es schon, bevor Computer erfunden wurden. Es bedurfte einiger erfahrener Logiker, um herauszufinden, wie man Subtraktionen durchführt (für eine Weile wurde die Theorie aufgestellt, dass nur Addition und Multiplikation möglich sind).
Wenn Sie lernen, wie Boolesche Werte und Zahlen
if
aus scheinbar nichts erfunden werden können, füllen Sie nicht mehr Benzin in Ihren Tank, aber Ihr Tank wird dadurch viel größer.quelle
-1
.Unreine Sprachen unterscheiden sich im Prinzip nicht wirklich von den bekannteren imperativen Sprachen, zumal jetzt, da viele funktionale Tricks kopiert wurden. Was ist anders ist der Stil - wie Sie Probleme lösen.
Unabhängig davon, ob Sie Haskell als rein oder die IO-Monade als Verunreinigung betrachten, der Haskell-Stil ist eine extreme Form dieses Stils und es lohnt sich, ihn zu lernen.
Die Haskell IO-Monade leitet sich aus der mathematischen Theorie der (natürlich) Monaden ab. Für imperative Programmierer halte ich es jedoch für sinnvoller, rückwärts zu Monaden zu gelangen.
Phase eins - Eine reine funktionale Sprache kann als Ergebnis leicht einen großen Zeichenfolgenwert zurückgeben. Diese große Zeichenfolge kann der Quellcode eines zwingenden Programms sein, das auf rein funktionale Weise aus einigen anforderungsspezifischen Parametern abgeleitet wird. Sie können dann einen Compiler auf "höherer Ebene" erstellen, der Ihren Codegenerator ausführt und dann den generierten Code automatisch in den Compiler für imperative Sprachen einspeist.
Phase zwei - anstatt Text-Quellcode zu generieren, generieren Sie einen stark typisierten abstrakten Syntaxbaum. Ihr imperativsprachiger Compiler wird in Ihren "übergeordneten" Compiler aufgenommen und akzeptiert den AST direkt als Quellcode. Dies ist viel näher an dem, was Haskell tut.
Dies ist jedoch immer noch umständlich. Zum Beispiel haben Sie zwei verschiedene Arten von Funktionen - die, die während der Code-Generierungsphase ausgewertet werden, und die, die ausgeführt werden, wenn das generierte Programm ausgeführt wird. Es ist ein bisschen wie die Unterscheidung zwischen Funktionen und Vorlagen in C ++.
Machen Sie also für Phase 3 die beiden gleich - dieselbe Funktion mit derselben Syntax kann teilweise während der "Codegenerierung" ausgewertet oder vollständig ausgewertet oder überhaupt nicht ausgewertet werden. Verwerfen Sie außerdem alle Schleifenkonstruktions-AST-Knoten zugunsten der Rekursion. Verwerfen Sie die Idee von AST-Knoten tatsächlich als eine spezielle Art von Daten - haben Sie keine AST-Knoten mit "Literalwert", sondern nur Werte usw.
Dies ist so ziemlich das, was die E / A-Monade tut - der Bind-Operator ist eine Möglichkeit, "Aktionen" zu erstellen, um Programme zu bilden. Es ist nichts Besonderes - nur eine Funktion. Viele Ausdrücke und Funktionen können während der "Codegenerierung" ausgewertet werden, aber bei denen, die von E / A-Nebenwirkungen abhängen, muss die Auswertung bis zur Laufzeit verzögert werden - nicht nach einer speziellen Regel, sondern als natürliche Folge der Datenabhängigkeiten in Ausdrücke.
Monaden im Allgemeinen sind nur Verallgemeinerungen - sie haben die gleiche Schnittstelle, implementieren die abstrakten Operationen jedoch unterschiedlich. Statt eine Beschreibung des imperativen Codes zu erhalten, werden sie stattdessen zu etwas anderem ausgewertet. Dasselbe Interface bedeutet, dass Sie einige Dinge mit Monaden tun können, ohne sich darum zu kümmern, welche Monade sich als nützlich herausstellt.
Diese Beschreibung wird zweifellos puristische Köpfe explodieren lassen, aber für mich erklärt sie einige der wahren Gründe, warum Haskell interessant ist. Es verwischt die Grenze zwischen Programmierung und Metaprogrammierung und verwendet die Werkzeuge der funktionalen Programmierung, um die imperative Programmierung neu zu erfinden, ohne dass eine spezielle Syntax erforderlich ist.
Eine Kritik an C ++ - Vorlagen ist, dass es sich um eine Art kaputte rein funktionale Subsprache in einer imperativen Sprache handelt. Um dieselbe Grundfunktion zur Kompilierungszeit und nicht zur Laufzeit zu evaluieren, muss sie mit einem völlig anderen Stil erneut implementiert werden der Codierung. In Haskell muss die Verunreinigung in ihrem Typ als solche gekennzeichnet sein, aber genau dieselbe Funktion kann sowohl im Sinne einer Metaprogrammierung als auch im Sinne einer Laufzeit-Nicht-Metaprogrammierung in demselben Programm bewertet werden - es gibt keine harte Linie zwischen Programmierung und Metaprogrammierung.
Das heißt, es gibt einige Metaprogrammierungsfunktionen, die Standard Haskell nicht ausführen kann, da Typen (und möglicherweise ein paar andere Funktionen) keine erstklassigen Werte sind. Es gibt jedoch Sprachvarianten, die versuchen, dies zu beheben.
Viele Dinge, die ich über Haskell gesagt habe, können in unreinen funktionalen Sprachen angewendet werden - und manchmal sogar in imperativen Sprachen. Haskell ist anders, weil Sie keine andere Wahl haben, als diesen Ansatz zu wählen - er zwingt Sie im Grunde, diesen Arbeitsstil zu erlernen. Sie können "C in ML schreiben", aber Sie können nicht "C in Haskell schreiben" - zumindest nicht, ohne zu lernen, was unter der Haube vor sich geht.
quelle
Ich persönlich kategorisiere Sprachen in drei Ebenen funktionaler Reinheit:
Reine Funktionssprachen - dh solche, die Ihr gesamtes Programm als reine Funktion behandeln und die Veränderbarkeit nur durch Interaktion mit der Laufzeit bewältigen - sind wahrscheinlich das kanonische Beispiel für Haskell
Unreine funktionale Sprachen - dh solche, die einen funktionalen Stil betonen, aber Nebenwirkungen zulassen. Clojure gehört eindeutig zu dieser Kategorie (es ermöglicht eine kontrollierte Mutation als Teil seines STM-Frameworks), auch OCaml oder F #
Multiparadigmasprachen - dies sind in erster Linie keine funktionalen Sprachen, können aber einen funktionalen Stil durch die Verwendung erstklassiger Funktionen unterstützen. Scala ist hier ein gutes Beispiel. Ich würde auch Common Lisp in diese Kategorie aufnehmen, und Sie könnten sogar einschließen Sprachen wie JavaScript .
In Ihrer Situation würde ich vorschlagen, zuerst Haskell und dann Clojure zu lernen. Dies war, was ich getan habe und es hat sehr gut für mich funktioniert! Haskell ist wunderschön und lehrt Sie die reinsten Funktionsprinzipien. Clojure ist viel pragmatischer und hilft Ihnen dabei, eine Menge zu erledigen, während Sie im Herzen dennoch sehr funktional sind.
Ich zähle die dritte Kategorie nicht wirklich als funktionale Sprachen (obwohl ich nach dem Erlernen von Haskell und Clojure oft die funktionalen Techniken nutze, wenn ich sie benutze!)
quelle
Wenn eine reine Funktionssprache solche ist, die nur reine Funktionen hat (Routinen, die keine Nebenwirkungen haben), dann ist es ein wenig sinnlos, weil sie keine Eingaben lesen oder Ausgaben schreiben kann;)
Da dies wirklich zum Lernen gedacht ist, denke ich, ist Isolation nicht unbedingt der richtige Weg. Funktionale Programmierung ist ein Paradigma. Es ist wichtig zu verstehen, welche Paradigmen für welche Probleme geeignet sind und, was noch wichtiger ist, wie sie am besten kombiniert werden können.
Anders als das, wenn Sie nach "Reinheit" suchen, möchten Sie vielleicht einen Blick auf Pure werfen . Beachten Sie jedoch, dass das Aufrufen von C-Routinen äußerst einfach ist und die Funktionen unsauber (aber auch sehr leistungsfähig) macht.
quelle
Keine ganz ernste Antwort, aber Unlambda muss ein Konkurrent sein. Mehr "pure Funktionalität" als SKI-Kombinatoren gibt es nicht.
quelle
Erlang, Haskell, Schema, Scala, Clojure und F #
Diese Frage würde wahrscheinlich am besten Sie , wie Sie bei der Suche helfen , gut .
quelle
set!
(unter anderem) ...