Beginnen wir in einer Gesamtsprache wie Agda. Dann ist dies, wie Gallais feststellt, nur dann sinnvoll, wenn Sie mit "leerer Typ" den Einheitentyp meinen, dh das 0-fache Tupel, das genau einen Wert hat. Der leere Typ kann als Summentyp mit 0 Fällen betrachtet werden und hat überhaupt keine Werte. In Agda können Sie leicht beweisen, dass dies Unit -> A
isomorph ist A
. In diesem Sinne können Sie sie als gleich betrachten, obwohl sie immer noch nicht buchstäblich gleich sind. Ich kann zum Beispiel keine Fallanalyse für eine durchführen Unit -> Bool
oder True : Bool
auf irgendetwas als Funktion anwenden .
Die Geschichte für Haskell ist ganz anders. () -> A
und A
sind semantisch nicht isomorphe Typen. Insbesondere () -> ()
vier Werte hat, während ()
nur hat 2. Die vier beobachtungs unterschiedliche Werte sind undefined
, \_ -> undefined
, \x -> x
, \_ -> ()
. Ist ()
also eigentlich kein Einheitentyp in dem Sinne, dass es genau eine Funktion gibt ()
. (In Agda hingegen können wir beweisen, dass wenn x : Unit
und y : Unit
dann gleich sind [definitiv, wenn wir Unit
mit der record
Syntax im Gegensatz zur data
Syntax definieren]. Das heißt, es Unit
hat nur einen Wert. Außerdem können wir das beweisen Unit
und A -> Unit
sind für jeden isomorph A
.)
Tatsächlich ist ein "leerer" Typ, wie er Void
definiert data Void
ist, in diesem Sinne eher ein Einheitentyp. Void
hat nur einen Wert, aber Void -> Void
immer noch zwei. Tatsächlich hat jeder Funktionstyp A -> B
mindestens zwei beobachtungsmäßig unterschiedliche Werte, nämlich undefined
und \_ -> undefined
. Daher hat Haskell keine echte Einheit oder keinen leeren Typ.
Vieles davon ist darauf zurückzuführen, dass Haskell eine nicht strenge Sprache ist und durch die Existenz von seq
(und seinen Äquivalenten) verärgert ist . Zum Beispiel ist die Unterscheidung zwischen undefined
und \_ -> undefined
nur mit zu sehen seq
. Wenn wir seq
Haskell und seine Äquivalente eliminieren Void
würden , würde dies als Einheitentyp dienen, ironischerweise jedoch immer noch nicht als leerer Typ.
Wenn Leute in Haskell über solche Dinge sprechen, tun sie normalerweise stillschweigend so, als sei Haskell eine Sprache, die sich besser benimmt als sie. Das heißt, sie gehen davon aus, dass es für ihre Zwecke keine Bottoms gibt, dh dass Sie in einer Gesamtsprache wie Agda arbeiten. Für die Gestaltung Ihres Codes ist dies normalerweise ausreichend. Es ist nicht üblich, dass wir uns um Unterteile kümmern oder diese erwarten. Diese Unterscheidungen können wichtig werden, wenn wir so etwas wie zirkuläre Programmierung durchführen oder wenn Sicherheitsgarantien unseres Programms auf diesen Eigenschaften beruhen, z. B. kann eine Funktion niemals aufgerufen werden, wenn sie einen leeren Typ als Domäne hat.