Was ist () in Haskell genau?
Bin ich beim Lesen Lernen Sie eine Haskell -, und in der Monade Kapitel, es scheint mir, dass ()
behandelt wird, als eine Art von "null" für jeden Typ. Wenn ich die Art der ()
im GHCi, bekomme ich
>> :t ()
() :: ()
ist eine sehr verwirrende Aussage. Es scheint, dass ()
ist ein Typ für sich. Ich bin verwirrt, wie passt es in die Sprache, und wie es scheint werden in der Lage zu stehen, der für jede Art.
- Es ist die
Unit
geben. Es hat genau einen Wert. . Aktionen, die Rückkehr keine interessanten Werte. - Ein Typ mit genau einem nicht-Wert unten.
- Was ist der Boden Wert?
- Boden-Wert ist ein Wert aus allen Typen. Es in der Regel bedeutet, dass kein anderer Wert zurückgegeben wurde (nontermination Funktion, Ausnahme etc.)
- Seltsam, dass keine Antwort Nennungen der Kategorie Theorie hier...
- ja, Einheit ist das terminal-Objekt und nichtig ist erste Objekt.
- Ähnlich wie
Bool
ist eine Art, die nur zwei Werte,Unit
ist ein Typ mit nur einem Wert,()
. Also, wo C verfügt über Funktionen, die feststellen, dass Ihre return-type alsvoid
[nicht wirklich ein Typ, aber eine dummy-Schlüsselwort mit der Bedeutung "es gibt keinen return-Wert"], der konsequentere Ansatz ist: "es gibt einen Rückgabe-Wert, aber es ist völlig uninteressant" --()
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
tl;dr
()
nicht fügen Sie eine "null" - Wert auf jede Art, die Hölle Nein;()
ist eine "stumpfe" Wert in einem Typ seiner eigenen:()
.Lassen Sie mich einen Schritt zurück aus der Frage einen moment und Adresse eine gemeinsame Quelle der Verwirrung. Eine wichtige Sache zu absorbieren, die beim lernen von Haskell ist die Unterscheidung zwischen seinen Ausdruck Sprache und Ihre Typ Sprache. Du bist wahrscheinlich bewusst, dass die beiden getrennt gehalten. Aber Sie ermöglicht, dass das gleiche symbol verwendet werden, in beide, und das ist das, was hier vor sich geht. Es gibt einfache textuelle Hinweise, Ihnen zu sagen, welche Sprache Sie suchen. Sie brauchen nicht zu analysieren, die ganze Sprache zu erkennen, diese cues.
Die oberste Ebene eines Haskell-Moduls lebt, wird standardmäßig im Ausdruck die Sprache. Sie definieren Funktionen durch das schreiben von Gleichungen zwischen Ausdrücken. Aber wenn Sie sehen foo :: bar in der expression-Sprache, es bedeutet, dass foo ist ein Ausdruck und bar ist seine Art. Also, wenn Sie Lesen
() :: ()
Sie sehen, eine Aussage, die sich die()
in der expression-Sprache mit der()
in der Art der Sprache. Die beiden()
Symbole bedeuten unterschiedliche Dinge, weil Sie nicht in der gleichen Sprache. Diese Wiederholung führt oft zu Verwirrung für Anfänger, bis der Ausdruck/Typ Sprache-Trennung installiert sich in Ihrem Unterbewusstsein, an dem Punkt wird es hilfsbereit Merksatz.Dem Stichwort
data
stellt einen neuen Datentyp Erklärung, mit einer sorgfältigen Mischung des Ausdrucks und geben Sie Sprachen, wie er sagt zuerst, was der neue Typ ist, und zweitens, was Ihre Werte sind.In so einer Deklaration, Typ-Konstruktor TyCon Hinzugefügt wird, die Art der Sprache und die ValCon Wert Konstruktoren Hinzugefügt werden, um den Ausdruck der Sprache (und deren Muster subsprache). In einem
data
Erklärung, die Dinge, die im argument Plätze für die ValCon s Ihnen sagen, die Arten gegeben, um die Argumente bei, dass ValCon wird die in Ausdrücken verwendet werden. Zum Beispiel,deklariert einen Typ-Konstruktor
Tree
für binäre Struktur-Typen speichern die Elemente, die am Knoten, deren Werte gegeben sind durch Wert-KonstruktorenLeaf
undNode
. Ich mag die Farbe von Typ-Konstruktoren (Baum) blau und Wert-Konstruktoren (Leaf, Node), red. Es sollte kein blau in Ausdrücken und (es sei denn, Sie sind mit erweiterten Funktionen) keine roten Typen. Die built-in-TypBool
deklariert werden könnte,hinzufügen blau
Bool
auf die Art der Sprache, und rotTrue
undFalse
zum Ausdruck Sprache. Leider ist meine markdown-fu ist nicht ausreichend, um die Aufgabe hinzuzufügen, Farben zu diesem post, so dass Sie nur lernen müssen, fügen Sie die Farben in Ihrem Kopf.Die "unit" - Typ verwendet
()
als ein besonderes symbol, aber es funktioniert, als ob erklärteBedeutung, dass ein notionally blau
()
ist ein Typ-Konstruktor in der Art der Sprache, aber das ein notionally rot()
ist ein Wert, der Konstruktor in der expression-Sprache, und in der Tat() :: ()
. [Es ist nicht das einzige Beispiel für solche Kalauer. Die Arten der größeren Tupeln, Folgen dem gleichen Muster: ein paar syntax ist wie, wenn vonhinzufügen (,), um sowohl den Typ und Ausdruck Sprachen. Aber ich schweife ab.
So der Typ
()
, ist die Aussprache oft "Einheit", ist eine Art, die einen Wert der Rede Wert: dieser Wert ist geschrieben()
aber in der expression-Sprache, und ist manchmal ausgesprochen "void". Ein Typ mit nur einem Wert ist nicht sehr interessant. Ein Wert vom Typ()
trägt null-bits von Informationen: Sie wissen schon, was es werden muss. So, während es ist nichts besonderes über die Art()
zu zeigen Nebenwirkungen, ist es oft zeigt sich die Wert-Komponente, die in einem monadischen Typ. Der monadischen Operationen, neigen dazu, die Typen die Aussehen wiewo ist der Rückgabetyp ist eine Art der Anwendung: die Funktion sagt Ihnen, welche Effekte möglich sind und das argument, erzählt Sie, welche Art von Wert produziert wird, durch den Betrieb. Zum Beispiel
gelesen (weil Anwendung associates auf der linken Seite ["wie wir alle haben in den sechziger Jahren", Roger Hindley]) als
hat einen Wert input type
s
-, Effekt-MonadeState s
, und der Wert der Ausgabe-Typ()
. Wenn Sie sehen()
als ein Wert, der die Nachrichtenart, das bedeutet nur "dieser Vorgang ist nur für seine Wirkung; der Wert an sich ist uninteressant". Ähnlicherzielt einen string zu
stdout
aber nicht zurück, nichts spannendes.Den
()
Typ ist auch nützlich als element-Typ für container-ähnlichen Strukturen, wo es anzeigt, dass die Daten aus nur einer Form, mit keine interessanten Nutzlast. Zum Beispiel, wennTree
erklärt wird wie oben, dannTree ()
ist die Art der binären Struktur Formen, Speicherung nichts von Interesse an den Knoten. Ähnlich[()]
ist der Typ der Listen von stumpf-Elemente, und wenn es nichts von Interesse in einer Liste, die Elemente, dann ist die einzige information, die er trägt, ist seine Länge.Zusammenfassend
()
ist ein Typ. Seinen Wert()
geschieht, die den gleichen Namen haben, aber das ist ok, da die Typ-und Ausdruck-Sprachen getrennt sind. Es ist nützlich, um eine Art repräsentieren "keine Informationen", denn im Kontext (z.B. einer Monade oder einem container), es sagt dir, dass nur der Kontext ist interessant.<pre>data <b>Bool</b> = <i>True</i> | <i>False</i></pre>
, aber ich fürchte, das ist das beste, was Sie tun können, angesichts der Beschränkungen, SO ist markdown. Die alternative wäre, Bilder zu verwenden.()
"void"? Das scheint, falsch, als "nichtig" wäre die Abwesenheit von beliebiger - Werte für mich.Den
()
Art gedacht werden kann, wie ein null-Tupel-element. Es ist ein Typ mit nur einem Wert, und es daher dort verwendet, wo Sie brauchen, um eine Art, aber Sie nicht wirklich brauchen, zu vermitteln jegliche Informationen. Hier ein paar Verwendungszwecke für diese.Monadischen Dinge wie
IO
undState
haben einen Rückgabewert, sowie Durchführung von Nebenwirkungen. Manchmal ist der einzige Punkt, der die operation durchführen, eine Nebenwirkung, wie das schreiben auf dem Bildschirm oder speichern einige Zustand. Für das schreiben auf dem BildschirmputStrLn
muß vom TypString -> IO ?
--IO
immer muss etwas zurück geben, aber hier gibt es nichts sinnvolles zurück. Also, welche Art sollten wir zurück? Wir könnten sagen, dass Int immer 0 zurück, aber das ist irreführend. So kehren wir()
, der Typ, der hat nur einen Wert (und damit keine nützlichen Informationen), um anzuzeigen, dass es nichts brauchbares zurück kommen.Ist es manchmal nützlich, eine Art, die keine brauchbaren Werte. Überlegen Sie, wenn Sie umgesetzt würde eine Art
Map k v
die Karten-Schlüssel von Typk
um Werte des Typsv
. Dann wollen Sie implementieren eineSet
, das ist wirklich ähnlich wie eine Karte, außer dass Sie nicht brauchen, die Wert Teil, nur die Tasten. In einer Sprache wie Java verwenden Sie boolsche Variablen als dummy-Wert geben, aber eigentlich wollen Sie einfach nur ein Typ, die hat keine brauchbaren Werte. Man könnte also sagentype Set k = Map k ()
Es sollte angemerkt werden, dass
()
ist nicht besonders magisch. Wenn Sie möchten, können Sie es speichern in eine variable und machen Sie einen pattern-match auf es (obwohl es nicht sehr viel Sinn):Heißt es die
Unit
geben, in der Regel verwendet, um darzustellen Nebenwirkungen. Man kann es vage alsVoid
in Java. Lesen Sie mehr hier und hier etc. Was verwirrend sein kann ist, dass()
syntaktisch repräsentiert, die den Typ und seine nur Wert, literal. Beachten Sie auch, dass es nicht ähnlich istnull
in Java, was bedeutet, dass eine Undefinierte Referenz -()
ist nur effektiv eine 0-size-Tupel.Unit
geben, aber auch literal repräsentiert nur den Wert von diesem Typ.Mag ich wirklich denken
()
durch Analogie mit Tupeln.(Int, Char)
ist der Typ aller Paare einerInt
und einChar
, so dass es die Werte sind alle möglichen Werte vonInt
gekreuzt mit alle möglichen Werte vonChar
.(Int, Char, String)
ist ähnlich wie der Typ der alle Tripel einerInt
eineChar
, und einString
.Es ist leicht zu sehen, wie Sie halten die Ausweitung dieses Muster nach oben, aber was ist unten?
(Int)
wäre das "1-Tupel" geben, die aus allen möglichen Werten vonInt
. Aber das würde analysiert werden, von Haskell als nur putting in KlammernInt
, und daher wird nur der TypInt
. Und Werte, die in dieser Art wäre(1)
,(2)
,(3)
usw, die würden auch nur bekommen, analysiert, wie gewöhnlicheInt
Werte in Klammern. Aber wenn Sie darüber nachdenken, eine "1-Tupel" ist genau das gleiche, wenn nur ein einzelner Wert, so gibt es keine Notwendigkeit, um tatsächlich existieren.Unten gehen einen Schritt weiter zur null-Tupel gibt uns
()
, das sollten alle möglichen Kombinationen von Werten in eine leere Liste von Typen. Nun, es gibt genau eine Möglichkeit, das zu tun, was ist enthalten, keine anderen Werte, so sollte es nur einen Wert in den Typ()
. Und durch die Analogie mit der Tupel-Wert-syntax, die wir schreiben können, dass der Wert als()
, die sicherlich sieht wie ein Tupel enthält keine Werte.Genau, wie es funktioniert. Es gibt keine Magie, und diese Art
()
und seinen Wert()
sind in keiner Weise besonders behandelt, die durch die Sprache.()
ist in der Tat nicht behandelt wird wie "ein null-Wert für jede Art" in den Monaden Beispiele in der LYAH Buch. Wenn sich die Art()
verwendet wird, die nur Wert, der zurückgegeben werden kann, ist()
. So dient es als eine Art zu explizit sagen, dass es nicht anderen Wert zurück. Und ebenso, wo ein anderer Typ ist, soll zurückgegeben werden, Sie nicht zurück()
.Die Sache im Auge zu behalten ist, dass, wenn eine Reihe von monadischen Berechnungen sind, komponierte zusammen mit
do
Blöcke oder Operatoren wie>>=
,>>
, etc, Sie werden Gebäude einen Wert vom Typm a
für einige Monadem
. Dass die Auswahlm
hat, bleiben die gleichen in der gesamten Komponenten (es gibt keine Möglichkeit, zu Komponieren, einMaybe Int
mit einemIO Int
so), aber diea
können und sehr oft ist anders, in jeder Phase.Also, wenn jemand klebt eine
IO ()
in der Mitte eineIO String
Berechnung, das ist nicht die()
als eine null in derString
geben, es ist einfach mit eineIO ()
auf dem Weg zum Aufbau einerIO String
die gleiche Weise könnte man verwenden eineInt
auf dem Weg zum Aufbau einerString
.Die Verwirrung kommt, die von anderen Programmier-Sprachen:
"void" bedeutet in den meisten imperativen Sprachen, dass es keine Struktur im Arbeitsspeicher speichern eines Werts. Es scheint widersprüchlich, weil "boolean" hat 2 Werte anstelle von 2 bits, während die "leere" hat keine bits statt keine Werte, aber es ist über was eine Funktion gibt, die in einem praktischen Sinn. Um genau zu sein: seine einzige Wert ist, verbraucht nicht viel Speicher.
Let ' s ignorieren Sie den Wert unten (geschrieben
_|_
) für einen moment...()
wird Einheit genannt, geschrieben wie ein null-Tupel. Es hat nur einen Wert. Und es wird nicht aufgerufenVoid
, weilVoid
hat ja noch nicht einmal Wert, so konnte nicht zurückgegeben werden, durch eine beliebige Funktion.Beobachten:
Bool
2 Werte hat (True
undFalse
),()
hat einen Wert (()
), undVoid
hat keinen Wert (es existiert nicht). Sie sind wie sets mit zwei/einen/keinen-Elemente. Die am wenigsten Speicher, den Sie brauchen, um zu speichern, deren Wert 1 bit /kein bisschen /unmöglich, beziehungsweise. Das bedeutet, dass eine Funktion zurückgibt, die ein()
zurückkehren können mit einen Ergebnis-Wert (der offensichtliche), die möglicherweise nutzlos für Sie.Void
auf der anderen Seite würde bedeuten, dass die Funktion niemals zurückkehren wird, und niemals geben Sie zu keinem Ergebnis, weil es nicht existieren würde zu keinem Ergebnis.Wenn Sie möchten, geben Sie "Wert" einen Namen ein, der eine Funktion gibt, die niemals zurückgegeben (ja, das klingt wie crazytalk), dann rufen Sie unten ("
_|_
", geschrieben wie ein umgekehrtes T). Es könnte eine Ausnahme sind oder infinity loop oder deadlock oder "einfach abwarten". (Einige Funktionen werden nur dann wieder Boden, wennn man Ihre Parameter unten.)Beim erstellen des kartesischen Produkts /a-Tupel von diesen Typen, Sie beobachten das gleiche Verhalten:
(Bool,Bool,Bool,(),())
hat 2·2·2·1·1=6 abweichende Werte.(Bool,Bool,Bool,(),Void)
ist wie die Menge {t,f}×{t,f}×{t,f}×{u}×{} die 2·2·2·1·0=0 Elemente, es sei denn, Sie zählen_|_
als Wert.Noch einem anderen Blickwinkel:
()
ist der Namen einer Gruppe, die enthält ein einzelnes element namens()
.Seine in der Tat etwas verwirrend, dass der name des sets und die
element in der es passiert das gleiche in diesem Fall.
Denken Sie daran: in Haskell ein Datentyp ist ein Satz, dessen mögliche Werte als Elemente in es.