Eine der definierenden Eigenschaften des Typs ⊥ oder leer ist, dass für jeden Typ A eine Funktion ⊥→A existiert . In der Tat gibt es eine einzigartige solche Funktion. Es ist daher vernünftig, diese Funktion als Teil der Standardbibliothek bereitzustellen. Oft wird es so etwas genannt . (In Systemen mit Untertypisierung kann dies einfach dadurch gehandhabt werden, dass ⊥ ein Untertyp jedes Typs ist. Dann lautet die implizite Konvertierung . Ein anderer verwandter Ansatz besteht darin , ⊥ als ∀ α zu definieren . Α kann einfach zu jedem Typ instanziiert werden.)Aabsurd
⊥absurd
⊥∀α.α
Sie möchten auf jeden Fall eine solche Funktion oder ein Äquivalent haben, weil Sie damit Funktionen nutzen können, die ⊥ erzeugen . Zum Beispiel, sagen wir mal ich eine Summe Typ gegeben bin E+A . Ich mache eine Fallanalyse und im E Fall werde ich eine Ausnahme mit throw:E→⊥ . Im A Fall würde ich verwenden f:A→B . Insgesamt möchte ich einen Wert vom Typ B also muss ich etwas tun, um aus einem ⊥ ein B . Das absurd
würde ich tun lassen.
Das heißt, es gibt nicht viele Gründe, Ihre eigenen Funktionen von ⊥→A zu definieren . Per Definition wären sie notwendigerweise Instanzen von absurd
. Sie können dies dennoch tun, wenn dies absurd
nicht von der Standardbibliothek bereitgestellt wird, oder Sie möchten eine typspezialisierte Version zur Unterstützung der Typüberprüfung / Inferenz. Sie können jedoch leicht Funktionen erzeugen, die zu einem Typ wie ⊥ → A instanziiert werden .⊥→A
Auch wenn es kaum einen Grund gibt, eine solche Funktion zu schreiben, sollte sie im Allgemeinen immer noch erlaubt sein . Ein Grund ist, dass es Tools / Makros zur Codegenerierung vereinfacht.
Derek Elkins verließ SE
quelle
(x ? 3 : throw new Exception())
für Analysezwecke durch so etwas wie ersetzt wird(x ? 3 : absurd(throw new Exception()))
?absurd
absurd
throw
Um das, was über die Funktion gesagt wurde, zu ergänzen, habe
absurd: ⊥ -> a
ich ein konkretes Beispiel, wo diese Funktion tatsächlich nützlich ist.Betrachten Sie den Haskell-Datentyp,
Free f a
der eine allgemeine Baumstruktur mitf
geformten Knoten und Blättern darstellt, diea
s enthalten :data Free f a = Op (f (Free f a)) | Var a
Diese Bäume können mit folgender Funktion gefaltet werden:
Kurz gesagt, diese Operation findet
alg
an den Knoten undgen
an den Blättern statt.Nun zum Punkt: Alle rekursiven Datenstrukturen können mit einem Festkomma-Datentyp dargestellt werden. In Haskell ist
Fix f
und kann dies definiert werden alstype Fix f = Free f ⊥
(dh Bäume mitf
-förmigen Knoten und keinen Blättern außerhalb des Funktorsf
). Traditionell hat diese Struktur auch eine Falte, genanntcata
:Das ist eine ziemlich gute Verwendung des Absurden: Da der Baum keine Blätter haben kann (da ⊥ keine anderen Einwohner hat als
undefined
), ist es niemals möglich, diegen
für diese Falte zu verwenden und das zuabsurd
veranschaulichen!quelle
Der unterste Typ ist ein Untertyp jedes anderen Typs, was in der Praxis äußerst nützlich sein kann. Beispielsweise muss der Typ von
NULL
in einer theoretischen typsicheren Version von C ein Subtyp jedes anderen Zeigertyps sein, andernfalls können Sie z. B. nicht zurückgeben,NULL
wo einchar*
erwartet wurde. Ebenso muss der Typ vonundefined
in der Theorie typsicherem JavaScript ein Subtyp jedes anderen Typs in der Sprache sein.exit()
throw()
Int
Int
exit()
quelle
NULL
Ist das nicht ein Einheitentyp, der sich von ⊥ unterscheidet? Welcher Typ ist leer?void*
umwandeln könnten , würden Sie einen bestimmten Typ dafür benötigen, der für jeden Zeigertyp verwendet werden könnte.<:
Ich kann mir eine Verwendung vorstellen, die als Verbesserung der Swift-Programmiersprache angesehen wurde.
Swift hat eine
maybe
Monade, DinkelOptional<T>
oderT?
. Es gibt viele Möglichkeiten, damit zu interagieren.Sie können das bedingte Auspacken wie verwenden
Sie können verwendet werden
map
, umflatMap
die Werte zu transformieren!
vom Typ " Force Unwrap"(T?) -> T
), um das gewaltsame Auspacken des Inhalts zu erzwingen, andernfalls wird ein Absturz ausgelöstDer Null-Koaleszenz-Operator (
??
vom Typ(T?, T) -> T
), um seinen Wert zu übernehmen oder auf andere Weise einen Standardwert zu verwenden:Leider gab es keine prägnante Möglichkeit zu sagen: "Fehler auspacken oder auslösen" oder "Mit einer benutzerdefinierten Fehlermeldung auspacken oder abstürzen". Etwas wie
Kompiliert nicht, weil
fatalError
es den Typ hat() -> Never
(()
istVoid
der Einheitentyp vonNever
Swift, der unterste Typ von Swift). Der Aufruf erzeugtNever
, was nicht mit demT
erwarteten richtigen Operanden von kompatibel ist??
.Um dem abzuhelfen, wurde der Vorschlag von Swift Evolution
SE-0217
- The Unwrap or Die veröffentlicht . Es wurde letztendlich abgelehnt , aber es weckte das Interesse,Never
einen Untertyp aller Art zu machen.Wenn
Never
als Subtyp aller Typen festgelegt wurde, kann das vorherige Beispiel kompiliert werden:weil die aufrufstelle von
??
typ hat(T?, Never) -> T
, der mit der(T?, T) -> T
signatur von kompatibel wäre??
.quelle
Swift hat einen Typ "Nie", der dem untersten Typ ziemlich ähnlich zu sein scheint: Eine Funktion, die als "Zurückgeben" deklariert ist, kann nie zurückgegeben werden, eine Funktion mit einem Parameter vom Typ "Nie" kann nie aufgerufen werden.
Dies ist nützlich in Verbindung mit Protokollen, bei denen es aufgrund des Typsystems der Sprache zu einer Einschränkung kommen kann, dass eine Klasse eine bestimmte Funktion haben muss, ohne dass diese Funktion jemals aufgerufen werden muss und ohne dass die Argumenttypen angegeben werden müssen wäre.
Für Details sollten Sie einen Blick auf die neueren Beiträge in der Mailingliste von swift-evolution werfen.
quelle