it-swarm.com.de

Gibt es eine praktische Verwendung für abhängige Typen?

Ich habe über dieses Ding namens abhängige Typen gelesen.

Stellen Sie sich zum Beispiel eine Funktion firstNPrimes(int n) vor, die ein Array der Länge n zurückgibt. Mit anderen Worten, der zurückgegebene Typ wäre int[n]. (In normalen Programmiersprachen ohne abhängige Typen können wir nur sagen, dass int[] Zurückgegeben wird, wobei der Typ die Array-Länge nicht angibt.)

Ich bin mir nicht ganz sicher, wie nützlich das ist. Ich nehme an, wenn Sie ein Kreuzprodukt hätten (in das diese erste Funktion als Argumente gesendet werden könnte):

int[3] Cross(int[3] A, int[3] B){..}

dies funktionierte nur mit dreidimensionalen Vektoren. Dann konnte der Compiler dies möglicherweise überprüfen und Zeigerprobleme vermeiden.

Gibt es echte praktische Anwendungen von abhängigen Typen, die für die tägliche Programmierung nützlich wären? Oder sind sie hauptsächlich nur für die abstrakte Logik nützlich?

7
zooby

Ich denke, was Ihnen möglicherweise fehlt, ist der Wert, von dem Sie abhängig sind, muss keine Konstante wie 3 sein. Die Länge wird häufig generisch angegeben, sodass Sie möglicherweise nicht die genaue Länge kennen, aber Sie können Einschränkungen für diese Länge zwischen angeben Ihre Rückgabewerte und verschiedene Argumente.

Es gibt viele Funktionen, die n > 0 Erfordern, wie zum Beispiel head.

Es gibt viele Funktionen, die einen Index annehmen, der innerhalb der Größe des Vektors liegen muss.

Es gibt viele Funktionen, die zwei Vektoren annehmen, die dieselbe Größe haben müssen, wie zum Beispiel ein Punktprodukt.

Mit der abhängigen Eingabe können Sie alle diese Einschränkungen beim Kompilieren überprüfen und am äußersten Rand Ihres Systems überprüfen.

19
Karl Bielefeldt

Ich nehme an, wenn Sie ein Kreuzprodukt hatten:

int[3] Cross(int[3] A, int[3] B){..}

dies funktionierte nur mit dreidimensionalen Vektoren. Dann konnte der Compiler dies möglicherweise überprüfen und Zeigerprobleme vermeiden.

Ja, ein Compiler könnte überprüfen, ob A und B an allen Stellen, an denen Cross verwendet wird, die richtige Größe haben, wenn die Größe Teil des Typsystems ist. Es könnte ein Fehler sein, wenn dies nicht der Fall ist. Und wenn es solche Fälle gibt, in denen dies nicht überprüft werden kann, entweder ein Fehler oder eine Warnung nach Ermessen des Sprachdesigners.

Gibt es echte praktische Anwendungen von abhängigen Typen, die für die tägliche Programmierung nützlich wären?

Dies ist eine Funktion, die Ihre Möglichkeiten einschränkt. Sie können nicht die falsche Größe des Arrays an Cross übergeben. Und das ist gut so. Diese Funktion kann das Lesen der Sprache erleichtern und es kann schwieriger werden, Fehler zu machen.

Darüber hinaus eignet es sich hervorragend für das automatische Marshalling, da die Größe des Puffers, der zum Übertragen von Informationen benötigt wird, Teil des Typsystems ist. Sie können ihn als Teil der Schnittstelle deklarieren und - wenn er richtig deklariert wird - einige Pufferüberlaufprobleme sparen.

Außerdem können Sie Datenbanktypen in Ihrem Code abgleichen. Zum Beispiel eine Zeichenfolge, die auf eine bestimmte Anzahl von Zeichen begrenzt ist.


Oder sind sie hauptsächlich nur für die abstrakte Logik nützlich?

Ein abhängiger Typ ist ein durch Werte parametrisierter Typ. Es passiert die ganze Zeit in - Drum Roll - C++. Sie können eine Vorlage mit Wertparametern erstellen.

Hier ist ein einfaches Beispiel:

template<int N>
struct S { int a[N]; };

Dies definiert ein Array-Mitglied mit der als Vorlagenargument angegebenen Größe.

Anwendungsbeispiel:

S<10> s; // s.a is an array of 10 int
s.a[9] = 4;

Beispiel aus cppreference .

So funktioniert std::array . std:array Ist eine Vorlage, die einen Typ und eine Größe annimmt. Sie können make_array verwenden, wenn Sie die Größe ableiten möchten. Wenn Sie über std::array Lesen, werden Sie finden Es ist weniger vielseitig als Arrays im C-Stil. Wie ich bereits sagte, schränkt diese Funktion Ihre Möglichkeiten ein. Im Gegenzug erhalten Sie eine statische Prüfung.

Wir könnten das C++ - Vorlagensystem verwenden, um die N-dimensionale Vektoralgebra zu definieren. Und da C++ die Spezialisierung unterstützt, können wir auch Operationen verarbeiten, die nicht allen Dimensionen gleich sind. Zum Beispiel ist ein Kreuzprodukt zweier 2D-Vektoren, das ein 2D-Vektor ist, nicht sinnvoll, aber ein Keilprodukt zweier 2D-Vektoren, das sich ergibt, ist die Länge des Kreuzprodukts der beiden vergrößerten 2D-Vektoren mit 0 in der dritten Dimension macht Sinn.


Als weiteres Beispiel werde ich mich an Ada wenden. Dies ist eine Subtypdeklaration in Ada:

subtype Count_To_Ten is Integer range 1 .. 10;

Das Obige definiert einen Typ Count_To_Ten, Alle Werte dieses Typs sind ebenfalls vom Typ Integer und liegen im Inklusivbereich von 1 bis 10.

Dann

subtype Ten_Characters is String (Count_to_Ten);

Das Obige definiert einen Typ Ten_Characters, Alle Werte dieses Typs sind Zeichenfolgen, und der Idex der Zeichen ist eine Count_to_Ten, Also eine Zeichenfolge mit 10 Zeichen.

Dieses Beispiel stammt aus Ada Programming/Type System .

Wir können diese 3D-Vektoren in Ada definieren:

type Axis is range 1 .. 3;
type Vector3 is array (Axis) of Integer;

Okay, nicht genau so, aber ich habe einen in Ada definierten Typ Vector3 In OpenGLAda - OpenGL-Bindung für Ada gefunden (diese verwenden eine Aufzählung für den Index und lassen Sie den Typ von angeben die Elemente, solange es arithmetische Operationen hat). Ich würde sagen, ja, das hat praktischen Nutzen: Videospiele.

6
Theraot

Nehmen wir ein Beispiel aus der Praxis. Oder besser, Real-Mars.

Der Mars Climate Observer der NASA stürzte auf den Mars, weil die Software Meter und Füße verwirrte. Dies war möglich, weil die Software alle Entfernungen nur als Zahlen behandelte. In der Physik sind Größen Einheiten zugeordnet. Füße und Meter sind unterschiedliche Einheiten, aber beide werden mit Längen verwendet. Sekunden und Meter sind unterschiedliche Einheiten für unterschiedliche Mengen.

In C++ können Sie dies im Typsystem ausdrücken. Und Sie können dies sogar verwenden, um abgeleitete Größen wie die Geschwindigkeit in Metern pro Sekunde (m ∙ s) abzuleiten-1) und Flächen in Quadratmetern (m2).

Wenn die NASA dies verwendet hätte, hätte sie Meter und Fuß vergleichen können. Der Compiler hätte bei der Umrechnung von Fuß in Meter den richtigen Skalierungsfaktor eingeführt.

6
MSalters