Karls Antwort ist gut. Hier ist eine zusätzliche Verwendung, von der ich glaube, dass sie noch niemand erwähnt hat. Die Art von
if E then A else B
sollte ein Typ sein, der alle Werte im Typ von A
und alle Werte im Typ von enthält B
. Wenn der Typ von B
ist Nothing
, kann der Typ des if
Ausdrucks der Typ von sein A
. Ich werde oft eine Routine erklären
def unreachable( s:String ) : Nothing = throw new AssertionError("Unreachable "+s)
zu sagen, dass der Code voraussichtlich nicht erreicht wird. Da es sich um den Typ handelt Nothing
, unreachable(s)
kann es jetzt in jedem if
oder (häufiger) verwendet werden, switch
ohne dass die Art des Ergebnisses beeinflusst wird. Zum Beispiel
val colour : Colour := switch state of
BLACK_TO_MOVE: BLACK
WHITE_TO_MOVE: WHITE
default: unreachable("Bad state")
Scala hat so einen Nichts-Typ.
Ein weiterer Anwendungsfall für Nothing
(wie in Karls Antwort erwähnt) ist List [Nothing]. Dabei handelt es sich um die Art von Listen, deren Mitglieder jeweils den Typ Nothing haben. Es kann also der Typ der leeren Liste sein.
Die Schlüsseleigenschaft Nothing
, die diese Anwendungsfälle funktionieren lässt, ist nicht, dass sie keine Werte haben - obwohl sie beispielsweise in Scala keine Werte haben -, dass sie ein Untertyp jedes anderen Typs sind.
Angenommen, Sie haben eine Sprache, in der jeder Typ denselben Wert enthält - nennen wir es ()
. In einer solchen Sprache kann der Einheitentyp, der ()
den einzigen Wert hat, ein Untertyp jedes Typs sein. Das macht es nicht zu einem Bottom-Typ im Sinne des OP; Dem OP war klar, dass ein Bottom-Typ keine Werte enthält. Da es sich jedoch um einen Typ handelt, der ein Untertyp jedes Typs ist, kann er in etwa die gleiche Rolle spielen wie ein unterer Typ.
Haskell macht die Dinge ein bisschen anders. In Haskell kann ein Ausdruck, der niemals einen Wert erzeugt, das Typschema haben forall a.a
. Eine Instanz dieses Typschemas wird mit jedem anderen Typ vereinheitlicht, sodass sie effektiv als unterer Typ fungiert, obwohl (Standard-) Haskell keine Vorstellung von Untertypisierung hat. Beispielsweise hat die error
Funktion aus dem Standardvorspiel ein Typschema forall a. [Char] -> a
. Du kannst also schreiben
if E then A else error ""
und der Typ des Ausdrucks A
ist für jeden Ausdruck der gleiche wie der Typ von A
.
Die leere Liste in Haskell hat das Typschema forall a. [a]
. Wenn A
ein Ausdruck ist, dessen Typ ein Listentyp ist, dann
if E then A else []
ist ein Ausdruck mit dem gleichen Typ wie A
.
void
Daten explizit definieren ...