Tipos del lenguaje de fórmulas M de Power Query

El lenguaje de fórmulas M de Power Query es un lenguaje de mashup de datos útil y expresivo. Pero tiene algunas limitaciones. Por ejemplo, no hay ninguna aplicación segura del sistema de tipos. En algunos casos, se necesita una validación más rigurosa. Afortunadamente, en M se proporciona una biblioteca integrada compatible con tipos para hacer factible una validación más segura.

Los desarrolladores deben tener un conocimiento exhaustivo del sistema de tipos para poder hacer esto con generalidad. Y, aunque en la especificación del lenguaje M de Power Query se explica correctamente el sistema de tipos, hay algunas sorpresas. Por ejemplo, para la validación de instancias de función se necesita una manera de comparar la compatibilidad de los tipos.

Si se explora el sistema de tipos de M con mayor detenimiento, muchos de estos problemas se pueden aclarar y los desarrolladores estarán capacitados para diseñar las soluciones que necesitan.

Para comprender la notación que se usa, debería bastar con conocimientos sobre el cálculo de predicados y la teoría informal de conjuntos.

PASOS PRELIMINARES

(1) B := { true; false }
B es el conjunto típico de valores booleanos

(2) N := { identificadores válidos de M }
N es el conjunto de todos los nombres válidos en M. Esto se define en otra parte.

(3) P := ⟨B, T
P es el conjunto de parámetros de función. Cada uno es posiblemente opcional y tiene un tipo. Los nombres de parámetro son irrelevantes.

(4) Pn := ⋃0≤i≤ni, Pi
Pn es el conjunto de todas las secuencias ordenadas de n parámetros de función.

(5) P* := ⋃0≤i≤∞Pi
P* es el conjunto de todas las secuencias posibles de parámetros de función, desde la longitud 0 en adelante.

(6) F := ⟨B, N, T
F es el conjunto de todos los campos de registro. Cada campo es posiblemente opcional, tiene un nombre y un tipo.

(7) Fn := ∏0≤i≤nF
Fn es el conjunto de todos los n campos de registro.

(8) F* := ( ⋃0≤i≤∞Fi ) ∖ { F | ⟨b1, n1, t1⟩, ⟨b2, n2, t2⟩ ∈ Fn1 = n2 }
F* es el conjunto de todos los conjuntos (de cualquier longitud) de campos de registro, excepto los conjuntos en los que más de un campo tiene el mismo nombre.

(9) C := ⟨N,T
C es el conjunto de tipos de columna, para las tablas. Cada columna tiene un nombre y un tipo.

(10) Cn ⊂ ⋃0≤i≤ni, C
Cn es el conjunto de todas las secuencias ordenadas de n tipos de columna.

(11) C* := ( ⋃0≤i≤∞Ci ) ∖ { Cm | ⟨a, ⟨n1, t1⟩⟩, ⟨b, ⟨n2, t2⟩⟩ ∈ Cmn1 = n2 }
C* es el conjunto de todas las combinaciones (de cualquier longitud) de tipos de columna, excepto aquellas en las que más de una columna tiene el mismo nombre.

TIPOS DE M

(12) TF := ⟨P, P*
Un tipo de función consta de un tipo de valor devuelto y una lista ordenada de cero o más parámetros de función.

(13) TL :=〖T
Un tipo de lista se indica mediante un tipo determinado (denominado "tipo de elemento") incluido entre llaves. Puesto que las llaves se usan en el metalanguage, 〖 〗 se usan corchetes en este documento.

(14) TR := ⟨B, F*
Un tipo de registro tiene una marca que indica si está abierto y tiene cero o más campos de registro sin ordenar.

(15) TRo := ⟨true, F

(16) TR := ⟨false, F
TRo and TR son métodos abreviados de notación para los tipos de registro abiertos y cerrados, respectivamente.

(17) TT := C*
Un tipo de tabla es una secuencia ordenada de cero o más tipos de columna, donde no hay conflictos de nombres.

(18) TP := { any; none; null; logical; number; time; date; datetime; datetimezone; duration; text; binary; type; list; record; table; function; anynonnull }
Un tipo primitivo es uno de esta lista de palabras clave de M.

(19) TN := { tn, u ∈ T | tn = u+null } = nullable t
Además, cualquier tipo se puede marcar como que acepta valores NULL mediante la palabra clave "nullable" .

(20) T := TFTLTRTTTPTN
El conjunto de todos los tipos de M es la unión de estos seis conjuntos de tipos:
tipos de función, tipos de lista, tipos de registros, tipos de tabla, tipos primitivos y tipos que aceptan valores NULL.

FUNCIONES

Una función se debe definir: NonNullable : TT
Esta función toma un tipo y devuelve un tipo que es equivalente, salvo que no se ajusta al valor NULL.

IDENTIDADES

Algunas identidades son necesarias para definir algunos casos especiales y también pueden ayudar a aclarar lo anterior.

(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

COMPATIBILIDAD DE TIPOS

Como se ha definido en otro lugar, un tipo de M es compatible con otro tipo de M solo si todos los valores que se ajustan al primer tipo también se ajustan al segundo.

Aquí se define una relación de compatibilidad que no depende de los valores que se ajustan y se basa en las propiedades de los propios tipos. Se asume que esta relación, como se define en este documento, es totalmente equivalente a la definición semántica original.

La relación "es compatible con": ≤ : BT × T
En la sección siguiente, una t minúscula siempre representa un tipo de M, un elemento de T.

Un símbolo Φ representará un subconjunto de F*, o bien de C*.

(28) tt
Esta relación es reflexiva.

(29) tatbtbtctatc
Esta relación es transitiva.

(30) none ≤ t ≤ any
Los tipos de M forman un enlace sobre esta relación; nonees la parte inferior yany la superior.

(31) ta, tbTNtataNonNullable(ta) ≤ NonNullable(tb)
Si dos tipos son compatibles, los equivalentes NonNullable también son compatibles.

(32) null ≤ tTN
El tipo primitivo null es compatible con todos los tipos que aceptan valores NULL.

(33) tTN ≤ anynonnull
Todos los tipos que no aceptan valores NULL son compatibles con anynonnull.

(34) NonNullable(t) ≤ t
Un tipo que no acepta valores NULL es compatible con el equivalente que acepta valores NULL.

(35) tTFt ≤ function
Todos los tipos de función son compatibles con función.

(36) tTLt ≤ list
Todos los tipos de lista son compatibles con lista.

(37) tTRt ≤ record
Todos los tipos de registro son compatibles con registro.

(38) tTTt ≤ table
Todos los tipos de tabla son compatibles con tabla.

(39) tatb ↔ 〖ta〗≤〖tb
Un tipo de lista es compatible con otro tipo de lista si los tipos de elemento son compatibles y viceversa.

(40) taTF = ⟨ pa, p* ⟩, tbTF = ⟨ pb, p* ⟩ ∧ papbtatb
Un tipo de función es compatible con otro tipo de función si los tipos devueltos son compatibles y las listas de parámetros son idénticas.

(41) taTRo, tbTRtatb
Un tipo de registro abierto nunca es compatible con un tipo de registro cerrado.

(42) taTR = ⟨false, Φ⟩, tbTRo = ⟨true, Φ⟩ → tatb
Un tipo de registro cerrado es compatible con un tipo de registro abierto que, de lo contrario, es idéntico.

(43) taTRo = ⟨true, (Φ, ⟨true, n, any⟩)⟩, tbTRo = ⟨true, Φ⟩ → tatbtbta
Se puede omitir un campo opcional con el tipo any al comparar dos tipos de registro abiertos.

(44) taTR = ⟨b, (Φ, ⟨β, n, ua⟩)⟩, tbTR = ⟨b, (Φ, ⟨β, n, ub⟩)⟩ ∧ uaubtatb
Dos tipos de registro que solo difieren en un campo son compatibles si el nombre y la opcionalidad del campo son idénticos, y los tipos de ese campo son compatibles.

(45) taTR = ⟨b, (Φ, ⟨false, n, u⟩)⟩, tbTR = ⟨b, (Φ, ⟨true, n, u⟩)⟩ → tatb
Un tipo de registro con un campo no opcional es compatible con un tipo de registro idéntico, pero opcional para ese campo.

(46) taTRo = ⟨true, (Φ, ⟨b, n, u⟩)⟩, tbTRo = ⟨true, Φ⟩ → tatb
Un tipo de registro abierto es compatible con otro tipo de registro abierto con un campo menos.

(47) taTT = (Φ, ⟨i, ⟨n, ua⟩⟩), tbTT = (Φ, ⟨i, ⟨n, ub⟩⟩) ∧ uaubtatb
Un tipo de tabla es compatible con un segundo tipo de tabla, que es idéntico pero para una columna con otro tipo, cuando los tipos de esa columna son compatibles.

REFERENCES

Microsoft Corporation (agosto de 2015)
Especificación del lenguaje de fórmulas de Microsoft Power Query para Excel [PDF]
Obtenido de https://msdn.microsoft.com/library/mt807488.aspx

Microsoft Corporation (n.d.)
Referencia de funciones M de Power Query [página web]
Obtenido de https://msdn.microsoft.com/library/mt779182.aspx