Typen in der Power Query-Formelsprache „M“

Die Power Query-Formelsprache „M“ ist eine nützliche und ausdrucksstarke Sprache für das Kombinieren von Daten. Dennoch gelten gewissen Einschränkungen für die Sprache. Das Typsystem wird beispielsweise nicht strikt durchgesetzt. In einigen Fällen ist eine strengere Prüfung erforderlich. Glücklicherweise bietet M eine integrierte Bibliothek mit Unterstützung für Typen, um diese genauere Prüfung auch zu ermöglichen.

Entwickler sollten über umfassende Kenntnisse des Typsystems verfügen, um diese Prüfungen allgemeingültig durchzuführen. Obwohl das Typsystem in der Power Query-Sprachspezifikation für M ausführlich erläutert wird, können nicht alle Aspekte umfassend abgedeckt werden. Für die Prüfung von Funktionsinstanzen ist beispielsweise eine Methode erforderlich, Typen auf ihre Kompatibilität zu prüfen.

Bei genauerer Kenntnis des Typsystem von M klären sich viele dieser Probleme, und Entwickler sind in der Lage, die benötigten Lösungen selbst zu erarbeiten.

Kenntnisse in Prädikatenkalkül und naiver Mengenlehre sollten ausreichen, um die verwendeten Notation zu verstehen.

EINLEITENDE HINWEISE

(1) B := { true; false }
B ist die übliche Menge der booleschen Werte.

(2) N := { valide M-Bezeichner }
N ist die Menge aller gültigen Namen in M. Diese werden an anderer Stelle definiert.

(3) P := ⟨B, T
P ist die Menge der Funktionsparameter. Jeder einzelne ist potenziell optional und verfügt über einen Typ. Parameternamen sind irrelevant.

(4) Pn := ⋃0≤i≤ni, Pi
Pn ist die Menge aller geordneten Sequenzen von n Funktionsparametern.

(5) P* := ⋃0≤i≤∞Pi
P* ist die Menge aller möglichen Sequenzen von Funktionsparametern der Länge 0 (Null) oder höher.

(6) F := ⟨B, N, T
F ist die Menge der Datensatzfelder. Jedes Feld ist potenziell optional und verfügt über einen Namen sowie einen Typ.

(7) Fn := ∏0≤i≤nF
Fn ist die Menge aller Mengen von n Datensatzfeldern.

(8) F* := ( ⋃0≤i≤∞Fi ) ∖ { F | ⟨b1, n1, t1⟩, ⟨b2, n2, t2⟩ ∈ Fn1 = n2 }
F* ist die Menge aller Mengen (jeder Länge) von Datensatzfeldern, außer den Mengen, in denen mehr als ein Feld denselben Namen aufweist.

(9) C := ⟨N,T
C ist die Menge der Spaltentypen für Tabellen. Jede Spalte besitzt einen Namen und einen Typ.

(10) Cn ⊂ ⋃0≤i≤ni, C
Pn ist die Menge aller geordneten Sequenzen von n Spaltentypen.

(11) C* := ( ⋃0≤i≤∞Ci ) ∖ { Cm | ⟨a, ⟨n1, t1⟩⟩, ⟨b, ⟨n2, t2⟩⟩ ∈ Cmn1 = n2 }
C* ist die Menge aller Kombinationen (jeder Länge) von Spaltentypen, außer denjenigen Kombinationen, in denen mehr als eine Spalte denselben Namen aufweist.

TYPEN IN M

(12) TF := ⟨P, P*
Ein Funktionstyp besteht aus einem Rückgabetyp und einer geordneten Liste von null oder mehr Funktionsparametern.

(13) TL :=〖T
Ein Listentyp wird von einem bestimmten Typ angegeben („Elementtyp“ genannt) und wird durch geschweifte Klammern eingeschlossen. Da geschweifte Klammern in der Metalanguage verwendet werden, 〖 〗 Klammern werden in diesem Dokument verwendet.

(14) TR := ⟨B, F*
Ein Datensatztyp verfügt über ein Flag, das angibt, ob der Typ offen ist, sowie über null oder mehr ungeordnete Datensatzfelder.

(15) TRo := ⟨true, F

(16) TR := ⟨false, F
TRo and TR sind abgekürzte Notationen für offene bzw. geschlossene Datensatztypen.

(17) TT := C*
Ein Tabellentyp ist eine geordnete Sequenz von null oder mehr Spaltentypen, wobei keine Namenskonflikte auftreten.

(18) TP := { any; none; null; logical; number; time; date; datetime; datetimezone; duration; text; binary; type; list; record; table; function; anynonnull }
Ein primitiver Typ ist ein Typ, der aus der Liste der M-Schlüsselworte stammt.

(19) TN := { tn, u ∈ T | tn = u+null } = nullable t
Jeder Typ kann mithilfe des Schlüsselworts „nullable“ zusätzlich als Nullwerte zulassend gekennzeichnet werden.

(20) T := TFTLTRTTTPTN
Die Menge aller M-Typen ist Menge der folgenden sechs Typenmengen:
Funktionstypen, Listentypen, Datensatztypen, Tabellentypen, primitive Typen und Nullwerte zulassende Typen.

FUNKTIONEN

Eine Funktion muss definiert werden: NonNullable : TT
Diese Funktion nimmt einen Typ und gibt einen entsprechenden Typen zurück. Ausnahme: Der Wert NULL wird nicht akzeptiert.

IDENTITÄTEN

Einige Identitäten sind erforderlich, um bestimmte Sonderfälle zu definieren, und können außerdem bei der Erläuterung des vorherigen Beispiels helfen.

(21) nullable any = any
(22) nullable anynonnull = any
(23) nullable null = null
(24) nullable none = null
(25) nullable nullable tT = nullable t
(26) NonNullable(nullable tT) = NonNullable(t)
(27) NonNullable(any) = anynonnull

TYPKOMPATIBILITÄT

Wie an anderer Stelle definiert, ist ein M-Typ dann und nur dann mit einem anderen M-Typ kompatibel, wenn alle Werte, die dem ersten Typ entsprechen, auch zum zweiten Typ gehören.

Hier wird eine Kompatibilitätsbeziehung definiert, die nicht von konformen Werten abhängt, sondern auf den Eigenschaften der Typen selbst basiert. Es wird angenommen, das diese Beziehung, so wie in diesem Dokument definiert, vollständig äquivalent zu der ursprünglichen semantischen Definition ist.

Die Kompatibilitätsbeziehung : ≤ : BT × T
Im folgenden Abschnitt steht der Kleinbuchstabe t immer für einen M-Typ, der ein Element von T ist.

Φ stellt eine Teilmenge von F* oder von C*.

(28) tt
Diese Beziehung ist reflexiv.

(29) tatbtbtctatc
Diese Beziehung ist transitiv.

(30) keine ≤ t ≤ beliebig viele
M-Typen bilden ein Raster über dieser Beziehung. none ist die Untergrenze und any die Obergrenze.

(31) ta, tbTNtataNonNullable(ta) ≤ NonNullable(tb)
Wenn zwei Typen kompatibel sind, sind auch NonNullable-Äquivalente kompatibel.

(32) null ≤ tTN
Der primitive Typ null ist mit allen nullable-Typen kompatibel.

(33) tTN ≤ anynonnull
Alle nonnullable-Typen sind kompatibel mit anynonnull.

(34) NonNullable(t) ≤ t
Ein NonNullable-Typ ist mit dem nullable-Äquivalent kompatibel.

(35) tTFt ≤ Funktion
Alle Funktionstypen sind kompatibel mit function.

(36) tTLt ≤ Liste
Alle Funktionstypen sind kompatibel mit list.

(37) tTRt ≤ Datensatz
Alle Funktionstypen sind kompatibel mit record.

(38) tTTt ≤ Tabelle
Alle Funktionstypen sind kompatibel mit table.

(39) tatb ↔ 〖ta〗≤〖tb
Ein Listentyp ist mit einem anderen Listentyp kompatibel, wenn die Elementtypen kompatibel sind. Gleiches gilt im umgekehrten Fall.

(40) taTF = ⟨ pa, p* ⟩, tbTF = ⟨ pb, p* ⟩ ∧ papbtatb
Ein Funktionstyp ist mit einem anderen Funktionstyp kompatibel, wenn die Rückgabetypen kompatibel und die Parameterlisten identisch sind.

(41) taTRo, tbTRtatb
Ein offener Datensatztyp ist niemals mit einem geschlossenen Datensatztyp kompatibel.

(42) taTR = ⟨false, Φ⟩, tbTRo = ⟨true, Φ⟩ → tatb
Ein geschlossener Datensatztyp ist mit einem sonst identischen offenen Datensatztyp kompatibel.

(43) taTRo = ⟨true, (Φ, ⟨true, n, any⟩)⟩, tbTRo = ⟨true, Φ⟩ → tatbtbta
Ein optionales Feld des Typs any kann ignoriert werden, wenn zwei offene Datensatztypen verglichen werden.

(44) taTR = ⟨b, (Φ, ⟨β, n, ua⟩)⟩, tbTR = ⟨b, (Φ, ⟨β, n, ub⟩)⟩ ∧ uaubtatb
Zwei Datensatztypen, die sich nur durch ein Feld unterscheiden, sind kompatibel, wenn der Name und die Optionalität des Felds identisch und die Typen der besagten Felder kompatibel sind.

(45) taTR = ⟨b, (Φ, ⟨false, n, u⟩)⟩, tbTR = ⟨b, (Φ, ⟨true, n, u⟩)⟩ → tatb
Ein Datensatztyp mit einem nicht optionalen Feld ist mit einem anderen Datensatztyp kompatibel, der bis auf die Tatsache identisch ist, dass das Feld optional ist.

(46) taTRo = ⟨true, (Φ, ⟨b, n, u⟩)⟩, tbTRo = ⟨true, Φ⟩ → tatb
Ein offener Datensatztyp ist mit einem anderen offenen Datensatztyp kompatibel, der ein Feld weniger enthält.

(47) taTT = (Φ, ⟨i, ⟨n, ua⟩⟩), tbTT = (Φ, ⟨i, ⟨n, ub⟩⟩) ∧ uaubtatb
Ein Tabellentyp ist mit einem zweiten Tabellentyp kompatibel, der bis auf eine Spalte identisch ist, die einen anderen Typ aufweist, wenn die Typen für diese Spalte kompatibel sind.

REFERENCES

Microsoft Corporation (August 2015)
Microsoft Sprachspezifikation für Power Query M [PDF]
Abgerufen von https://msdn.microsoft.com/library/mt807488.aspx

Microsoft Corporation (o. J.)
Funktionsreferenz für Power Query M
Abgerufen von https://msdn.microsoft.com/library/mt779182.aspx