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:
1,a,b
? Was ist der Typ von einer Projektion im Allgemeinen? 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:
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:
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:
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:
Ein Beispiel für Select
s, das wir definieren könnten, wäre:
Dieser Select
-Typ würde die Applicative
-Schnittstelle implementieren, sodass wir mehrere Select
s zu einem einzigen Select
kombinieren könnten. Zum Beispiel:
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
:
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:
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.
Tags und Links haskell types relational-database theory hindley-milner