Tipos na linguagem de fórmula do Power Query M
A Linguagem de Fórmula M do Power Query é uma linguagem de mashup de dados útil e expressiva. Mas tem algumas limitações. Por exemplo, não existe uma aplicação rigorosa do sistema de tipos. Em alguns casos, é necessária uma validação mais rigorosa. Felizmente, o M fornece uma biblioteca integrada com suporte para tipos para viabilizar uma validação mais forte.
Os desenvolvedores devem ter uma compreensão completa do tipo de sistema para fazer isso com qualquer generalidade. E, embora a especificação da linguagem Power Query M explique bem o sistema de tipos, deixa algumas surpresas. Por exemplo, a validação de instâncias de função requer uma maneira de comparar tipos para compatibilidade.
Ao explorar o sistema do tipo M com mais cuidado, muitas dessas questões podem ser esclarecidas e os desenvolvedores terão o poder de criar as soluções de que precisam.
O conhecimento do cálculo de predicados e da teoria ingênua dos conjuntos deve ser adequado para compreender a notação utilizada.
PRELIMINARES
(1) B := { verdadeiro; falso }
B é o conjunto típico de valores booleanos
(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 dos parâmetros são irrelevantes.
(4) Pn := ⋃0≤i≤n ⟨i, Pi⟩
Pn é o conjunto de todas as sequências ordenadas de n parâmetros de função.
(5) P* := ⋃0≤i≤∞P i
P* é o conjunto de todas as sequências possíveis de parâmetros de função, do comprimento 0 para cima.
(6) F := ⟨B, N, T⟩
F é o conjunto de todos os campos de registo. Cada campo é possivelmente opcional, tem um nome e um tipo.
(7) Fn := ∏0≤i≤n F
Fn é o conjunto de todos os conjuntos de n campos de registro.
(8) F* := ( ⋃0≤i≤∞ Fi ) ∖ { F | ⟨b1, n1, t1⟩, ⟨b2, n2, t2⟩ ∈ F ⋀ n1 = n2 }
F* é o conjunto de todos os conjuntos (de qualquer comprimento) de campos de registo, exceto os 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) Cn ⊂ ⋃0≤i≤n ⟨i, C⟩
Cn é o conjunto de todas as sequências ordenadas de n tipos de coluna.
(11) C* := ( ⋃0≤i≤∞ Ci ) ∖ { Cm | ⟨a, ⟨n1, t1⟩⟩, ⟨b, ⟨n2, t2⟩⟩ ∈ Cm ⋀ n1 = n2 }
C* é o conjunto de todas as combinações (de qualquer comprimento) de tipos de colunas, exceto aquelas em que mais de uma coluna tem o mesmo nome.
M TIPOS
(12) TF := ⟨P, P⟩*
Um Tipo de Função consiste em um tipo de retorno e uma lista ordenada de parâmetros de função zero ou mais.
(13) TL :=〖T〗
Um tipo de lista é indicado por um determinado tipo (chamado de "tipo de item") envolto em chaves encaracoladas.
Uma vez que os suportes encaracolados são usados na metalinguagem, 〖 〗 Os parênteses são usados neste documento.
(14) TR := ⟨B, F⟩*
Um Tipo de Registro tem um sinalizador que indica se está "aberto" e zero ou mais campos de registro não ordenados.
(15) TRo := ⟨verdadeiro, F⟩
(16) TR• := ⟨falso, F⟩
TRo e TR• são atalhos notacionais para os tipos de registro aberto e fechado, respectivamente.
(17) TT := C *
Um Tipo de Tabela é uma sequência ordenada de tipos de coluna zero ou mais, onde não há colisões de nomes.
(18) TP := { qualquer; nenhum; nulo; lógico; número; hora; data; datetime; datetimezone; duração; texto; binário; tipo; lista; registro; tabela; função; anynonnull }
Um Tipo Primitivo é um desta lista de palavras-chave M.
(19) TN := { tn, u ∈ T | tn = u+null } = anulável t
Qualquer tipo também pode ser marcado como anulável, usando a palavra-chave "nullable ".
(20) T := tf ∪ tl ∪ tr ∪ tt t ∪ tp ∪ tn
O conjunto de todos os tipos M é a união destes seis conjuntos de tipos:
Tipos de função, tipos de lista, tipos de registro, tipos de tabela, tipos primitivos e tipos anuláveis.
FUNCTIONS
Uma função precisa ser definida: NonNullable : T ← T
Essa função usa um tipo e retorna um tipo que é equivalente, exceto que 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 o acima.
(21) anulável qualquer = qualquer
(22) anulável anynonnull = any
(23) nulo anulável = nulo
(24) anulável nenhum = nulo
(25) anulável t anulável ∈ T = anulável t
(26) NonNullable(nullable t ∈ T) = NonNullable(t)
(27) NonNullable(any) = anynonnull
COMPATIBILIDADE DE TIPO
Tal como definido noutras rubricas, um tipo M é compatível com outro tipo M se e apenas se todos os valores conformes com o primeiro tipo também estiverem em conformidade com o segundo tipo.
Aqui é definida uma relação de compatibilidade que não depende de valores conformes e é baseada nas propriedades dos próprios tipos. Prevê-se que esta relação, tal como definida neste documento, seja completamente equivalente à definição semântica original.
A relação "é compatível com" : ≤ : B ← T × T
Na seção abaixo, um t minúsculo sempre representará um tipo M, um elemento de T.
Um Φ representará um subconjunto de F*, ou de C*.
(28) t ≤ t
Esta relação é reflexiva.
(29) ta ≤ tb ∧ tb ≤ tc → ta ≤ t c
Esta relação é transitiva.
(30) Nenhuma ≤ não ≤ qualquer
Os tipos M formam uma rede sobre esta relação; nenhum é o fundo, e qualquer é o topo.
(31) ta, tb ∈ TN ∧ ta ≤ ta → Não anulável(ta) ≤ Não anulável(tb)
Se dois tipos são compatíveis, então os equivalentes NonNullable também são compatíveis.
(32) nulo ≤ t ∈ TN
O tipo primitivo null é compatível com todos os tipos anuláveis.
(33) t ∉ TN ≤ anynonnull
Todos os tipos não anuláveis são compatíveis com anynonnull.
(34) Não anulável(t) ≤ t
Um tipo NonNullible é compatível com o equivalente anulável.
(35) t ∈ TF → t ≤ função
Todos os tipos de função são compatíveis com a função.
(36) t ∈ TL → t ≤ lista
Todos os tipos de lista são compatíveis com list.
(37) t ∈ TR → t ≤ record
Todos os tipos de registo são compatíveis com o registo.
(38) t ∈ TT → t ≤ quadro
Todos os tipos de tabela são compatíveis com tabela.
(39) ta ≤ tb ↔ 〖ta〗≤〖tb〗
Um tipo de lista é compatível com outro tipo de lista se os tipos de item forem compatíveis e vice-versa.
(40) ta ∈ TF = ⟨ pa, p* ⟩, tb ∈ TF = ⟨ pb, p* ⟩ ∧ pa ≤ pb → ta ≤ t b
Um tipo de função é 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) ta ∈ TRo, tb ∈ TR• → ta ≰ t b
Um tipo de registo aberto nunca é compatível com um tipo de registo fechado.
(42) ta ∈ TR• = ⟨falso, Φ⟩, tb ∈ TRo = ⟨verdadeiro, Φ⟩ → ta ≤ t b
Um tipo de registo fechado é compatível com um tipo de registo aberto idêntico.
(43) ta ∈ TRo = ⟨verdadeiro, (Φ, ⟨verdadeiro, n, qualquer⟩)⟩, tb ∈ TRo = ⟨verdadeiro, Φ⟩ → ta ≤ tb ∧ tb ≤ t a
Um campo opcional com o tipo any pode ser ignorado ao comparar dois tipos de registro abertos.
(44) ta ∈ TR = ⟨b, (Φ, ⟨β, n, ua⟩)⟩, tb ∈ TR = ⟨b, (Φ, ⟨β, n, ub⟩)⟩ ∧ ua ≤ ub → ta ≤ t b
Dois tipos de registro que diferem apenas por um campo são compatíveis se o nome e a opcionalidade do campo forem idênticos e os tipos desse campo forem compatíveis.
(45) ta ∈ TR = ⟨b, (Φ, ⟨falso, n, u⟩)⟩, tb ∈ TR = ⟨b, (Φ, ⟨verdadeiro, n, u⟩)⟩ → ta ≤ t b
Um tipo de registo com um campo não opcional é compatível com um tipo de registo idêntico, mas para esse campo é opcional.
(46) ta ∈ TRo = ⟨verdadeiro, (Φ, ⟨b, n, u⟩)⟩, tb ∈ TRo = ⟨verdadeiro, Φ⟩ → ta ≤ t b
Um tipo de registo aberto é compatível com outro tipo de registo aberto com menos um campo.
(47) ta ∈ TT = (Φ, ⟨i, ⟨n, ua⟩⟩), tb ∈ TT = (Φ, ⟨i, ⟨n, ub⟩⟩) ∧ ua ≤ ub → ta ≤ t b
Um tipo de tabela é compatível com um segundo tipo de tabela, que é idêntico, mas para uma coluna com um tipo diferente, quando os tipos para essa coluna são compatíveis.
REFERÊNCIAS
Microsoft Corporation (agosto de 2015)
Especificação da linguagem de fórmula do Microsoft Power Query para Excel [PDF]
Obtido em https://msdn.microsoft.com/library/mt807488.aspx
Microsoft Corporation (s.d.)
Referência da função Power Query M [página Web]
Obtido em https://msdn.microsoft.com/library/mt779182.aspx