Warum sind typsichere relationale Operationen so schwierig?

9

Ich habe versucht, ein relationales Problem in Haskell zu kodieren, als ich herausfinden musste, dass dies auf eine Art und Weise sicher ist, ist alles andere als offensichtlich. Z.B. eine bescheidene

%Vor%

wirft bereits eine Reihe von Fragen auf:

  • Was ist der Typ dieser Funktion?
  • Wie ist der Typ der Projektion 1,a,b ? Was ist der Typ von einer Projektion im Allgemeinen?
  • Was ist der Ergebnistyp und wie drücke ich die Beziehung zwischen dem Ergebnistyp und der Projektion aus?
  • Was ist der Typ einer solchen Funktion, die eine gültige Projektion akzeptiert?
  • Wie kann ich beim Kompilieren ungültige Projektionen erkennen?
  • Wie würde ich eine Spalte zu einer Tabelle oder zu einer Projektion hinzufügen?

Ich glaube, dass sogar die PL / SQL-Sprache von Oracle nicht ganz richtig ist. Während Ungültige Projektionen meist zur Kompilierzeit erkannt werden, gibt es eine große Anzahl von Typfehlern, die nur zur Laufzeit angezeigt werden. Die meisten anderen Bindungen an RDBMS (z. B. Java's jdbc und Perls DBI) verwenden SQL, das in Strings enthalten ist, und geben somit die Typensicherheit vollständig auf.

Weitere Untersuchungen haben ergeben, dass es einige Haskell-Bibliotheken gibt ( HList , vinyl und TRex), die typsichere erweiterbare Datensätze und mehr zur Verfügung stellen. Aber diese Bibliotheken benötigen alle Haskell-Erweiterungen wie DataKinds , FlexibleContexts und viele mehr. Außerdem sind diese Bibliotheken nicht einfach zu bedienen und riechen nach Tricks, zumindest für nicht initialisierte Beobachter wie mich.

Dies legt nahe, dass typsichere relationale Operationen nicht gut in das funktionale Paradigma passen, zumindest nicht so, wie es in Haskell implementiert ist.

Meine Fragen sind die folgenden:

  • Was sind die grundlegenden Ursachen für diese Schwierigkeit, relationale Operationen typsicher zu modellieren? Wo steht Hindley-Milner? Oder liegt das Problem bereits am typisierten Lambda-Kalkül?
  • Gibt es ein Paradigma, in dem relationale Operationen erstklassige Bürger sind? Und wenn ja, gibt es eine Implementierung in der realen Welt?
Martin Drautzburg 02.05.2015, 08:35
quelle

1 Antwort

4

Definieren wir eine Tabelle, die für einige Spalten als Typ mit zwei Typparametern indiziert ist:

%Vor%

k ist ein (möglicherweise verschachteltes) Tupel aller Spalten, für die die Tabelle indiziert ist. v ist ein (möglicherweise verschachteltes) Tupel aller Spalten, für die die Tabelle nicht indiziert ist.

So zum Beispiel, wenn wir die folgende Tabelle hatten

%Vor%

... und es wurde in der ersten Spalte indiziert, dann wäre der Typ:

%Vor%

Wenn es jedoch in der ersten und zweiten Spalte indiziert wäre, wäre der Typ:

%Vor%

Table würde die Klassen Functor , Applicative und Alternative implementieren. Mit anderen Worten:

%Vor%

So Joins würde als implementiert werden:

%Vor%

Dann hätten Sie einen separaten Typ, den wir Select nennen würden. Dieser Typ hat auch zwei Typparameter:

%Vor%

A Select würde eine Reihe von Zeilen vom Typ v aus der Tabelle verbrauchen und ein Ergebnis vom Typ r erzeugen. Mit anderen Worten, wir sollten eine Funktion vom Typ haben:

%Vor%

Ein Beispiel für Select s, das wir definieren könnten, wäre:

%Vor%

Dieser Select -Typ würde die Applicative -Schnittstelle implementieren, sodass wir mehrere Select s zu einem einzigen Select kombinieren könnten. Zum Beispiel:

%Vor%

Das wäre analog zu diesem SQL:

%Vor%

Allerdings wird unsere Tabelle oft mehrere Spalten haben, daher müssen wir einen Select auf eine einzelne Spalte fokussieren. Nennen wir diese Funktion Focus :

%Vor%

Damit wir Dinge schreiben können wie:

%Vor%

Wenn wir also etwas schreiben wollten wie:

%Vor%

Das würde diesem Haskell-Code entsprechen:

%Vor%

Sie fragen sich vielleicht, wie man Select und Table implementieren könnte.

Ich beschreibe, wie man Table in diesem Post implementiert:

Ссылка

... und Sie können Select nur wie folgt implementieren:

%Vor%

Beachten Sie auch, dass dies nicht die einzige Möglichkeit ist, Table und Select zu implementieren. Sie sind nur eine einfache Implementierung, um Sie zu starten, und Sie können sie bei Bedarf verallgemeinern.

Was ist mit der Auswahl von Spalten aus einer Tabelle? Nun, Sie können definieren:

%Vor%

Also, wenn du es machen wolltest:

%Vor%

... Sie würden schreiben:

%Vor%

Der wichtige Vorteil ist, dass Sie eine relationale API in Haskell ohne irgendwelche ausgefallenen Systemerweiterungen implementieren können.

    
Gabriel Gonzalez 02.05.2015 18:13
quelle