Tipos na linguagem de fórmula do Power Query M

A linguagem de fórmula do Power Query M é uma linguagem de mashup de dados útil e expressiva. No entanto, ela tem algumas limitações. Por exemplo, não há nenhuma imposição forte do sistema de tipos. Em alguns casos, uma validação mais rigorosa é necessária. Felizmente, o M fornece uma biblioteca interna compatível com tipos para viabilizar uma validação mais forte.

Os desenvolvedores devem ter uma compreensão abrangente do sistema de tipos para que possam fazer isso com qualquer generalidade. E embora a especificação da linguagem do Power Query M explique bem o sistema de tipos, ela ainda deixa algumas surpresas. Por exemplo, a validação de instâncias de função requer uma forma de comparar tipos quanto à compatibilidade.

Ao explorar o sistema de tipos do M mais cuidadosamente, muitos desses problemas poderão ser esclarecidos e os desenvolvedores se capacitarão a criar as soluções de que precisam.

O conhecimento de cálculo de predicados e a teoria ingênua dos conjuntos devem ser adequados para a compreensão da notação usada.

ETAPAS PRELIMINARES

(1) B := { true; false }
B é o conjunto típico de valores boolianos

(2) N := { identificadores M válidos }
N é o conjunto de todos os nomes válidos em M. Isso é definido em outro lugar.

(3) P := ⟨B, T
P é o conjunto de parâmetros de função. Cada um é possivelmente opcional e tem um tipo. Os nomes de parâmetro são irrelevantes.

(4) P n := 0≤i≤ni, Pi
Pn é o conjunto de todas as sequências ordenadas de n parâmetros de função.

(5) P* := 0≤i≤∞ Pi
P* é o conjunto de todas as sequências possíveis de parâmetros de função, em ordem crescente, começando pelas de comprimento 0.

(6) F := ⟨B, N, T
F é o conjunto de todos os campos de registro. Cada campo é possivelmente opcional, tem um nome e um tipo.

(7) Fn := 0≤i≤n F
Fn é o conjunto de todos os campos de registro.

(8) F* := ( ⋃0≤i≤∞ Fi ) ∖ { F | ⟨b 1 , n 1 , t 1 ⟩, ⟨b 2 , n 2 , t 2 ⟩ ∈ Fn 1 = n2 }
F* é o conjunto de todos os conjuntos (de qualquer tamanho) de campos de registro, exceto pelos conjuntos em que mais de um campo tem o mesmo nome.

(9) C := ⟨N,T
C é o conjunto de tipos de coluna para tabelas. Cada coluna tem um nome e um tipo.

(10) Cn0≤i≤ni, C
Cn é o conjunto de todas as sequências de tipos de coluna n.

(11) C* := ( ⋃0≤i≤∞ Ci ) ∖ { Cm | ⟨a, ⟨n 1 , t 1 ⟩⟩, ⟨b, ⟨n 2 , t 2 ⟩⟩ ∈ C mn 1 = n2 }
C* é o conjunto de todas as combinações (de qualquer tamanho) de tipos de coluna, exceto aquelas em que mais de uma coluna tem o mesmo nome.

TIPOS DE M

(12) TF := ⟨P, P*
Um tipo de função consiste em um tipo de retorno e uma lista ordenada de zero ou mais parâmetros de função.

(13) TL :=〖T
Um tipo de lista é indicado por um determinado tipo (chamado de "tipo de item") encapsulado entre chaves. Já que as chaves são usadas na metalinguagem, os colchetes 〖 〗 são usados neste documento.

(14) TR := ⟨B, F*
Um tipo de registro tem um sinalizador que indica se ele está "aberto" e tem zero ou mais campos de registro não ordenados.

(15) TRo := ⟨true, F

(16) TR := ⟨false, F
TRo e TR são atalhos de notação para tipos de registro abertos e fechados, respectivamente.

(17) TT := C*
Um tipo de tabela é uma sequência ordenada de zero ou mais tipos de coluna, em que não há conflitos de nome.

(18) TP := { any; none; null; logical; number; time; date; datetime; datetimezone; duration; text; binary; type; list; record; table; function; anynonnull }
Um tipo primitivo é um contido nesta lista de palavras-chave do M.

(19) TN := { t n , u ∈ T | t n = u+null } = nullable t
Qualquer tipo também pode ser marcado como permitindo valor nulo, usando a palavra-chave "nullable".

(20) T := T F T L T R T T T P TN
O conjunto de todos os tipos do M é a união de todos estes seis conjuntos de tipos: Tipos de função, tipos de lista, tipos de registro, tipos de tabela, tipos primitivos e tipos que permitem valor nulo.

FUNÇÕES

É necessário definir uma função: NonNullable : TT
Essa função usa um tipo e retorna um tipo equivalente, exceto pelo fato de que esse segundo tipo não está em conformidade com o valor nulo.

IDENTIDADES

Algumas identidades são necessárias para definir alguns casos especiais e também podem ajudar a elucidar os casos acima.

(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

COMPATIBILIDADE DE TIPO

Conforme ressaltado em outra parte deste documento, um tipo M será compatível com outro tipo M se e somente se todos os valores que estiverem em conformidade com o primeiro tipo também estiverem em conformidade com o segundo tipo.

Temos definida aqui uma relação de compatibilidade que não depende de valores estarem em conformidade e é baseada nas propriedades dos tipos propriamente ditos. Espera-se que essa relação, conforme definido neste documento, seja completamente equivalente à definição semântica original.

A relação "é compatível com": ≤ : BT × T
Na seção abaixo, uma letra t minúscula sempre representará um tipo do M, um elemento de T.

Um Φ representará um subconjunto de F* ou de C*.

(28) tt
Essa relação é reflexiva.

(29) t at bt bt ct atc
Essa relação é transitiva.

(30) none ≤ t ≤ any
Os tipos do M formam uma malha sobre essa relação; none é a parte inferior e any é a parte superior.

(31) t a , t bT Nt at aNonNullable(t a ) ≤ NonNullable(tb )
Se dois tipos forem compatíveis, os equivalentes NonNullable também serão compatíveis.

(32) null ≤ tTN
O tipo primitivo null é compatível com todos os tipos que permitem valor nulo.

(33) tTN ≤ anynonnull
Todos os tipos NonNullable são compatíveis com anynonnull.

(34) NonNullable(t) ≤ t
Um tipo NonNullable é compatível com o equivalente anulável.

(35) tT Ft ≤ function
Todos os tipos de função são compatíveis com function.

(36) tT Lt ≤ list
Todos os tipos de lista são compatíveis com list.

(37) tT Rt ≤ record
Todos os tipos de registro são compatíveis com record.

(38) tT Tt ≤ table
Todos os tipos de tabela são compatíveis com table.

(39) t at b ↔ 〖t a 〗≤〖tb
Um tipo de lista será compatível com outro tipo de lista se os tipos de item forem compatíveis e vice-versa.

(40) t aT F = ⟨ p a , p * ⟩, t bT F = ⟨ p b , p * ⟩ ∧ p ap bt atb
Um tipo de função será compatível com outro tipo de função se os tipos de retorno forem compatíveis e as listas de parâmetros forem idênticas.

(41) t aTRo, t bTRt atb
Um tipo de registro aberto nunca é compatível com um tipo de registro fechado.

(42) t aTR = ⟨false, Φ ⟩, t bTRo = ⟨true, Φ ⟩ → t atb
Um tipo de registro fechado é compatível com outro tipo de registro quase idêntico, exceto por ser aberto.

(43) t aTRo = ⟨true, ( Φ , ⟨true, n, any⟩)⟩, t bTRo = ⟨true, Φ ⟩ → t at bt bta
Um campo opcional com o tipo any pode ser ignorado ao comparar dois tipos de registros abertos.

(44) t aT R = ⟨b, (Φ, ⟨β, n, u a⟩)⟩, t bT R = ⟨b, (Φ, ⟨β, n, u b⟩)⟩ ∧ u au bt atb
Dois tipos de registro que diferem somente por um campo serão compatíveis se o nome e a opcionalidade do campo forem idênticos e os tipos desse campo forem compatíveis.

(45) t aT R = ⟨b, (Φ, ⟨false, n, u⟩)⟩, t bT R = ⟨b, (Φ, ⟨true, n, u⟩)⟩ → t atb
Um tipo de registro com um campo não opcional é compatível com um tipo de registro quase idêntico, exceto por ter esse campo como opcional.

(46) t aTRo = ⟨true, ( Φ , ⟨b, n, u⟩)⟩, t bTRo = ⟨true, Φ ⟩ → t atb
Um tipo de registro aberto é compatível com outro tipo de registro aberto que tem um campo a menos.

(47) t aT T = ( Φ , ⟨i, ⟨n, u a ⟩⟩), t bT T = ( Φ , ⟨i, ⟨n, u b ⟩⟩) ∧ u au bt atb
Um tipo de tabela é compatível com um segundo tipo de tabela quase idêntico, exceto por ter uma coluna com um tipo diferente, quando os tipos dessa coluna são compatíveis.

REFERENCES

Microsoft Corporation (agosto de 2015)
Especificação de linguagem de fórmula do Microsoft Power Query para Excel [PDF]
Recuperado de https://msdn.microsoft.com/library/mt807488.aspx

Microsoft Corporation. (n. d.)
Referência de função do Power Query M [página da Web]
Recuperado de https://msdn.microsoft.com/library/mt779182.aspx