Ich bin irgendwie neu in Haskell und ich habe Schwierigkeiten zu verstehen, wie abgeleitete Typen und solche Arbeiten.
%Vor%Was genau bedeutet das?
%Vor%Was sind die Unterschiede zwischen diesen?
Und der abgeleitete Typ von
foldr Karte ist [a] - & gt; [a - & gt; a] - & gt; [a]
aber warum ist das so?
Danke!
Wenn Sie das Beispiel von
nehmen %Vor%Dies bedeutet, dass map zwei Argumente benötigt
Und es kommt zurück
Sie können das Muster bereits sehen, aber es wird klarer, wenn wir 'a' und 'b'
ersetzenAlso wird diese Typdefinition
sein %Vor%Nun ist es also eine Funktion, die einen String zurücknimmt und Int und eine Liste von Strings zurückgibt und eine Liste von Ints zurückgibt.
Sagen Sie unsere Funktion, die einen String übernimmt und zurückgibt, und Int ist %code% . %code% verwendet den String, den Sie ihm geben, um ihn in etwas anderes zu konvertieren. Da wir es hier in einen Int-Kontext stellen, wird die Zeichenkette in int
konvertiert %Vor%Dies wird zu
führen %Vor%weil %code% die Funktion %code% und Maps für jedes Element der Liste übernimmt (anwendet). Sie müssen nicht %code% sagen, es ist ein Argument wie %code% oder %code% , weil %code% das für Sie erledigt.
Und das ist wirklich alles, was dazu gehört. Der Typ einer Funktion sagt nur, welche Typen sie benötigt und welchen Typ sie zurückgibt. Natürlich gibt es auch Curry, aber dazu wirst du später entweder absichtlich kommen oder nicht! Es bedeutet im Grunde, dass eine Funktion nicht viele Argumente akzeptiert, sondern nur eins. Nehmen wir an, Sie nehmen die Funktion %code% . Wenn Sie %code% auswerten, gibt es eine Funktion zurück, die eine andere Zahl übernimmt, die zu %code% hinzugefügt wird, und da es hier eine andere Zahl gibt, %code% , wird diese verwendet. Sie hätten es als %code% auswerten und weitergeben können, eventuell später die Nummer hinzugefügt. Es ist klarer, wenn Sie nicht die Infix-Syntax von %code% haben. Es hätte %code% geschrieben werden können, also wird diese Anweisung zuerst %code% , was vom Typ ist (vereinfacht! Ich werde hier nicht die Klasse Num-Klasse einführen) %code% . Also %code% (oder %code% ) ist nur eine weitere Funktion, auf die Sie einen Wert anwenden können. An diesem Punkt kann das Ergebnis zu 3 rechnen.
So sieht das in der Praxis aus: (Ignoriere den %code% -Teil hier, wenn er dich verwirrt, es ist ein Konzept, von dem du später mehr erfährst. Ersetze einfach die %code% -Typen hier durch %code% , wenn du willst, und Ignoriere den %code% Teil komplett.)
%Vor%Und zu Ihrer zweiten Frage: Sie definieren abgeleitete Typen NICHT ALLE. Sie werden "abgeleitet" genannt, weil der Compiler / Interpreter die Typen selbst "leitet" (liest: berechnet), ohne sie explizit zu benennen.
Über die %code% Unterschiede: Sie alle machen genau dasselbe: Reduzieren Sie eine Liste auf einen einzelnen Wert. Der Unterschied zwischen den Funktionen ist lediglich die interne Definition. %code% faltet die Liste von links und %code% macht sie rechts.
Um eine Liste zusammenzufassen, können Sie alle so verwenden ...
%Vor%Sie sehen, mit Ausnahme von foldl1, liefern Sie eine Funktion zum Falten, einen Startwert (Akkumulator) und eine Liste zum Falten. %code% hat einen eigenen Akku, du gibst ihn nicht selbst.
In der Praxis sollten Sie besser %code% verwenden, da es im Gegensatz zu %code% für BIG-Listen geeignet ist, ohne aufgrund eines Stack-Überlaufs abzustürzen (tee, hee). Und Ausnahme von dieser Regel ist %code% (beachte das "'"!) In %code% - es ist eine strikte Faltung, die auch für große Listen geeignet ist.
Wenn Sie Funktionen ihre Typen selbst geben möchten (wenn Sie sie geschrieben haben), betrachten Sie dieses Beispiel:
%Vor%Oder auf haskellische Weise
%Vor%In der ersten Zeile der beiden Beispiele ( %code% ) suchen Sie. So können Sie den Compiler oder Interpreter zwingen, die Funktion zu identifizieren - Sie können sie dann weglassen, und der Compiler / Interpreter wird sie herausfinden (und manchmal sogar besser, als man zuerst denken würde)
Funktionen in Haskell verwenden eine Notation namens Curry. Eine Definition wie
%Vor%bedeutet, dass %code% eine Funktion ist, die zwei %code% s akzeptiert und einen Wert vom Typ ganz rechts zurückgibt (der wiederum %code% ist). Genauer gesagt bedeutet currying, dass Sie mit teilweise angewandten Funktionen arbeiten, die Ihnen erlauben, Code wie
zu schreiben %Vor%Kleinbuchstaben in Typensignaturen weisen auf eine sogenannte -Typ-Variable hin, die als Platzhalter für jeden möglichen Typ angesehen werden kann.
Die Definition
%Vor%bedeutet also Für alle Typen %code% und %code% , %code% nimmt eine Funktion von %code% bis %code% und eine Liste von %code% , von denen es eine Liste von erzeugt %code% s .
Nehmen wir ein Beispiel
%Vor%Wir sehen, die angegebene Liste ist eine Liste von %code% , also %code% . Darüber hinaus sollte %code% %code% auf jedes Element anwenden, was ein %code% zurückgibt. Da %code% auf den Typ %code% der Definition passen muss, können wir folgern, dass %code% .
Unser Ausdruck gibt ein %code% zurück, also ist das Ergebnis ein %code% .
Um solche Signaturen noch deutlicher zu machen, können wir sie mit einer ausführlicheren Syntax schreiben
%Vor%Dies gibt nun explizit an, dass %code% mit allen Typen %code% und %code% arbeiten soll.
Für die Falten werfen Sie einen Blick auf ihre Definitionen . Angesichts des obigen Wissens sollten die Typ-Signaturen selbsterklärend sein, wenn klar ist, was die Funktionen tun sollen.
Beispiel: %code%
Die Signatur von %code% wird.
%Vor%Sie können diese auch erhalten, indem Sie einfach %code% in den Haskell-Interpreter (GHCi) eingeben.
In Haskell ist eine Kleinschreibung eine Typvariable. Während %code% nur %code% , %code% oder %code% bedeutet, könnte %code% oder %code% oder %code% oder ein anderer Typ bedeuten. Der Schlüssel ist, dass alle %code% s vom selben Typ sind. Und alle %code% s sind vom selben Typ.
Zum Beispiel verwendet %code% als erstes Argument eine Funktion, die eine Variable vom Typ %code% und eine andere vom Typ %code% zurückgibt. Dann gibt %code% eine neue Funktion zurück, die eine Liste vom Typ %code% übernimmt. Diese neue Funktion gibt eine Liste vom Typ %code% zurück.
Angenommen, Sie hätten eine Funktion %code% , die einen Wert zu einer Ganzzahl hinzufügt. %code% würde letztendlich eine Liste [2,3,4] zurückgeben.
Die frühere Definition von %code% mit den ersetzten Typvariablen würde wie folgt aussehen:
%code%
und %code% , BTW, würden wie
aussehen%code%
Der Grund, warum es lustig geschrieben ist, ist, dass Sie Funktionen teilweise anwenden können. Hier werde ich eine neue Funktion basierend auf der teilweisen Anwendung der Karte machen:
%Vor%Dann könnten Sie
verwenden %Vor%würde das gleiche Ergebnis erzeugen
Die Kleinbuchstaben in den Typdeklarationen sind Typ Variablen . Das heißt, wenn ein %code% vorhanden ist, muss dies derselbe Typ sein.
Klammerausdrücke (zB %code% ) Teilausdrücke neigen dazu, zu bedeuten, dass die Funktion eine Funktion als einen ihrer Parameter akzeptiert.
Rechteckige Klammern zeigen eine Liste von etwas an.
So akzeptiert %code% diese Argumente:
und erzeugt %code% eine Liste als Ergebnis.
Wir können %code% auf die gleiche Weise dekodieren:
Haskell kann jedoch eine nette Sache machen, und das heißt, wenn Sie ein Argument weglassen, gibt es eine Funktion zurück, die die verbleibende Signatur hat. Daher wird %code% häufig verwendet, um Funktionen zu ketten.
Nehmen wir an, wir haben 2 Funktionen %code% , die ein Zeichen annehmen und dessen Integer-Repräsentation und %code% zurückgeben, was seinem Argument 32 hinzufügt.
Wenn wir %code% schreiben, hat die Funktion upcaseVal jetzt die Signatur %code% , weil die Funktion %code% sie mit %code% belassen hätte und wir sie in der Funktionsdefinition ersetzen würden.
Also müsste %code% so sein:
Somit ist der letzte Typ:
%Vor%Aber ich denke, das muss Sie nicht so sehr stören, da der Compiler die meiste Zeit damit beschäftigt ist.