Vor einiger Zeit, glaube ich, habe ich bei Stack Overflow jemanden sagen sehen, dass Haskell-Literale als Funktionen betrachtet werden können, die mit nichts funktionieren. Das macht für mich Sinn, aber ich erinnere mich, dass jemand anderes ihm vehement widersprach.
Wenn ich das richtig verstehe, sind alle Werte in primitiven Typen oder zumindest die in Bool
Typkonstruktoren, und Typkonstruktoren sind eine spezielle Art von Funktion für den Typ. Da die Werte mögen 2.87
, True
oder 'f'
haben keine Parameter an sie übergeben es scheint , wie es nicht die Semantik der Sprache bewirken würde , ob Sie an sie denken nur als Elemente ihrer Art oder eine Funktion von einem Typ nichts in ihrer Art enthält , das gibt immer ihren Wert zurück. Ist etwas falsch daran, auf diese Weise an Literale zu denken?
quelle
Antworten:
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 istA
. 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ührenUnit -> Bool
oderTrue : Bool
auf irgendetwas als Funktion anwenden .Die Geschichte für Haskell ist ganz anders.
() -> A
undA
sind semantisch nicht isomorphe Typen. Insbesondere() -> ()
vier Werte hat, während()
nur hat 2. Die vier beobachtungs unterschiedliche Werte sindundefined
,\_ -> 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 wennx : Unit
undy : Unit
dann gleich sind [definitiv, wenn wirUnit
mit derrecord
Syntax im Gegensatz zurdata
Syntax definieren]. Das heißt, esUnit
hat nur einen Wert. Außerdem können wir das beweisenUnit
undA -> Unit
sind für jeden isomorphA
.)Tatsächlich ist ein "leerer" Typ, wie er
Void
definiertdata Void
ist, in diesem Sinne eher ein Einheitentyp.Void
hat nur einen Wert, aberVoid -> Void
immer noch zwei. Tatsächlich hat jeder FunktionstypA -> B
mindestens zwei beobachtungsmäßig unterschiedliche Werte, nämlichundefined
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 zwischenundefined
und\_ -> undefined
nur mit zu sehenseq
. Wenn wirseq
Haskell und seine Äquivalente eliminierenVoid
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.
quelle
ST
sicherer Zwang,eqT
GADTs, Typenfamilien, sehr allgemeine Typklassen (inkohärent?!) Usw. sehen etwas umständlich aus. Hier könnte es sogar ein Return-of-Investment-Problem geben: Selbst wenn man (?) Eine formale Semantik zu hohen Kosten erstellen könnte, hätte dies eine entsprechend große Auswirkung? Wahrscheinlich nicht. Und in 2 Jahren würde eine neue GHC-Erweiterung es brechen ... :-(