Ich habe das Buch Learn You a Haskell bis zu dem Punkt gelesen, an dem sie Monaden und ähnliches vorstellen. Diese sind für mich so eingängig, dass ich einfach nicht mehr versuchen möchte, sie zu lernen.
Aber ich möchte es wirklich versuchen.
Ich frage mich, ob ich zumindest die fortgeschrittenen Konzepte für eine Weile vermeiden kann und erst anfange, die anderen Teile der Sprache zu verwenden, um eine Menge praktischer Aufgaben mit den grundlegenderen Teilen von Haskell zu erledigen, dh Funktionen, Standard-E / A, Dateihandhabung, Datenbankanbindung und dergleichen.
Ist dies ein vernünftiger Ansatz, um zu lernen, wie man Haskell benutzt?
Antworten:
Lassen Sie uns zunächst unterscheiden zwischen dem Erlernen der abstrakten Konzepte und dem Erlernen spezifischer Beispiele .
Sie werden nicht allzu weit kommen, wenn Sie alle spezifischen Beispiele ignorieren, und das aus dem einfachen Grund, weil sie absolut allgegenwärtig sind. Tatsächlich existieren die Abstraktionen zu einem großen Teil, weil sie die Dinge, die Sie sowieso tun würden, mit den spezifischen Beispielen vereinen.
Die Abstraktionen selbst sind zwar nützlich , aber nicht sofort notwendig. Man kann ziemlich weit kommen, wenn man die Abstraktionen komplett ignoriert und einfach die verschiedenen Typen direkt verwendet. Sie werden sie irgendwann verstehen wollen, aber Sie können später immer noch darauf zurückkommen. Tatsächlich kann ich fast garantieren, dass Sie sich in diesem Fall die Stirn schlagen und sich fragen, warum Sie die ganze Zeit auf die harte Tour verbracht haben, anstatt die praktischen Allzweckwerkzeuge zu verwenden.
Nehmen Sie
Maybe a
als Beispiel. Es ist nur ein Datentyp:Es ist alles andere als selbstdokumentierend; Es ist ein optionaler Wert. Entweder Sie haben "nur" etwas von Typ
a
, oder Sie haben nichts. Angenommen, Sie haben eine Art Nachschlagefunktion, die darauf hinweistMaybe String
,String
dass ein möglicherweise nicht vorhandener Wert gesucht wird . Sie stimmen also mit dem Wert überein, um festzustellen, um welchen Wert es sich handelt:Das ist alles!
Wirklich, sonst brauchen Sie nichts. Kein
Functor
s oderMonad
s oder irgendetwas anderes. Diese drücken übliche Arten der Verwendung vonMaybe a
Werten aus ... aber sie sind nur Redewendungen, "Entwurfsmuster", wie auch immer Sie es nennen möchten.Der einzige Ort, an dem Sie es wirklich nicht ganz vermeiden können, ist mit
IO
, aber das ist sowieso eine mysteriöse Black Box. Es lohnt sich also nicht zu versuchen, zu verstehen, was es bedeutet, alsMonad
was oder was auch immer.In der Tat, hier ist ein Spickzettel für alles, was Sie für den Moment wirklich wissen müssen
IO
:Wenn etwas einen Typ
IO a
hat, bedeutet das, dass es eine Prozedur ist , die etwas tut und einena
Wert ausspuckt .Wenn Sie einen Codeblock mit der
do
Notation haben, schreiben Sie so etwas:... bedeutet , die Prozedur rechts von auszuführen
<-
und das Ergebnis dem Namen links zuzuweisen.Wenn Sie so etwas haben:
... bedeutet, den Wert des einfachen Ausdrucks (keine Prozedur) rechts von
=
dem Namen links zuzuweisen .Wenn Sie etwas dort ablegen, ohne einen Wert zuzuweisen:
... bedeutet, eine Prozedur auszuführen und alles zu ignorieren, was sie zurückgibt. Einige Prozeduren haben den Typ
IO ()
- der()
Typ ist eine Art Platzhalter, der nichts aussagt , was bedeutet, dass die Prozedur etwas tut und keinen Wert zurückgibt . So ähnlich wie einevoid
Funktion in anderen Sprachen.Wenn Sie den gleichen Vorgang mehrmals ausführen, kann dies zu unterschiedlichen Ergebnissen führen. das ist so eine idee. Aus diesem Grund gibt es keine Möglichkeit, das
IO
aus einem Wert zu "entfernen" , da etwas inIO
kein Wert ist, sondern eine Prozedur, um einen Wert zu erhalten.Die letzte Zeile in einem
do
Block muss eine einfache Prozedur ohne Zuweisung sein, wobei der Rückgabewert dieser Prozedur der Rückgabewert für den gesamten Block wird. Wenn der Rückgabewert einen bereits zugewiesenen Wert verwenden soll, nimmt diereturn
Funktion einen einfachen Wert und gibt Ihnen eine No-Op-Prozedur, die diesen Wert zurückgibt.Davon abgesehen hat es nichts Besonderes
IO
. Diese Prozeduren sind eigentlich reine Werte, und Sie können sie weitergeben und auf verschiedene Arten kombinieren. Nur wenn sie in einemdo
Block ausgeführt werden, der von irgendwoher aufgerufen wirdmain
, tun sie etwas.In so etwas wie diesem äußerst langweiligen, stereotypen Beispielprogramm:
... Sie können es wie ein Imperativprogramm ablesen. Wir definieren eine Prozedur mit dem Namen
hello
. Bei der Ausführung wird zuerst eine Prozedur zum Drucken einer Nachricht ausgeführt, in der Sie nach Ihrem Namen gefragt werden. Als nächstes führt es eine Prozedur aus, die eine Eingabezeile liest und das Ergebnis zuweistname
. dann weist es dem Namen einen Ausdruck zumsg
; dann druckt es die Nachricht aus; Dann wird der Name des Benutzers als Ergebnis des gesamten Blocks zurückgegeben. Da aname
istString
, bedeutet dies, dasshello
es sich um eine Prozedur handelt, die a zurückgibtString
, also einen Typ hatIO String
. Und jetzt können Sie diese Prozedur an einer anderen Stelle ausführen, genau wie sie ausgeführt wirdgetLine
.Pfff, Monaden. Wer braucht sie?
quelle
Sie sind wesentlich. Ohne sie ist es nur allzu einfach, Haskell als eine weitere imperative Sprache zu verwenden, und obwohl Simon Peyton Jones Haskell einmal als "die beste imperative Programmiersprache der Welt" bezeichnet hat, verpassen Sie immer noch das Beste.
Monaden, Monadentransformationen, Monoide, Funktoren, anwendbare Funktoren, entgegengesetzte Funktoren, Pfeile, Kategorien usw. sind Entwurfsmuster. Sobald Sie die spezifische Sache, die Sie machen, in eine von ihnen eingepasst haben, können Sie auf eine Fülle von Funktionen zurückgreifen, die abstrakt geschrieben sind. Diese Typenklassen sind nicht nur dazu da, Sie zu verwirren, sie sind dazu da, Ihnen das Leben zu erleichtern und Sie produktiver zu machen. Sie sind meiner Meinung nach der größte Grund für die Prägnanz eines guten Haskell-Codes.
quelle
Ist es unbedingt notwendig, wenn Sie nur etwas zum Laufen bringen wollen? Nein.
Ist es notwendig, wenn Sie schöne idiomatische Haskell-Programme schreiben möchten? Absolut.
Bei der Programmierung in Haskell ist es hilfreich, zwei Dinge zu beachten:
Das Typensystem hilft Ihnen dabei. Wenn Sie Ihr Programm aus hochpolymorphem, typenklassenintensivem Code zusammensetzen, können Sie sehr oft in die wunderbare Situation geraten, in der der Typ der gewünschten Funktion Sie zu der (einen einzigen!) Korrekten Implementierung führt .
Die verschiedenen verfügbaren Bibliotheken wurden unter Verwendung des Prinzips # 1 entwickelt.
Wenn ich also ein Programm in Haskell schreibe, beginne ich damit, die Typen zu schreiben. Dann beginne ich von vorne und schreibe einige allgemeinere Typen auf (und wenn es sich um Instanzen bestehender Typenklassen handelt, umso besser). Dann schreibe ich einige Funktionen, die mir Werte der Typen geben, die ich will. (Dann spiele ich mit ihnen
ghci
und schreibe vielleicht ein paar QuickCheck-Tests.) Und schließlich klebe ich alles zusammenmain
.Es ist möglich, hässliches Haskell zu schreiben, das gerade etwas zum Laufen bringt. Aber wenn Sie diese Phase erreicht haben, gibt es noch so viel zu lernen.
Viel Glück!
quelle