Typen
Een typewaarde is een waarde die andere waarden classificeert . Een waarde die door een type wordt geclassificeerd, wordt gezegd dat deze voldoet aan dat type. Het M-typesysteem bestaat uit de volgende typen:
Primitieve typen, die primitieve waarden classificeren (
binary
,date
,datetime
,datetimezone
,duration
, , ,list
logical
null
number
record
text
,time
, )type
en ook een aantal abstracte typen (function
,table
,any
en )anynonnull
none
Recordtypen, waarmee recordwaarden worden geclassificeerd op basis van veldnamen en waardetypen
Lijsttypen, waarmee lijsten worden geclassificeerd met één itembasistype
Functietypen, waarmee functiewaarden worden geclassificeerd op basis van de typen van hun parameters en retourwaarden
Tabeltypen, waarmee tabelwaarden worden geclassificeerd op basis van kolomnamen, kolomtypen en sleutels
Null-typen, waarmee de waarde null wordt geclassificeerd naast alle waarden die zijn geclassificeerd door een basistype
Typetypen, waarmee waarden worden geclassificeerd die typen zijn
De set primitieve typen omvat de typen primitieve waarden en een aantal abstracte typen, die typen zijn die geen unieke classificatie van waarden hebben: function
, table
, any
en anynonnull
none
. Alle functiewaarden voldoen aan het abstracte type function
, alle tabelwaarden aan het abstracte type table
, alle waarden aan het abstracte type any
, alle niet-null-waarden voor het abstracte type anynonnull
en geen waarden voor het abstracte type none
. Een expressie van het type none
moet een fout veroorzaken of niet beëindigen omdat er geen waarde kan worden geproduceerd die voldoet aan het type none
. Houd er rekening mee dat de primitieve typen function
en table
abstract zijn omdat er geen functie of tabel rechtstreeks van deze typen is. De primitieve typen record
en list
zijn niet-abstract omdat ze een geopende record vertegenwoordigen zonder gedefinieerde velden en een lijst met elk type.
Alle typen die geen lid zijn van de gesloten set primitieve typen plus hun nullable tegenhangers worden gezamenlijk aangepaste typen genoemd. Aangepaste typen kunnen worden geschreven met behulp van:type-expression
type-expressie:
primaire expressie
type
primair type
type:
primaire expressie
primair type
primair type:
primitief-type
recordtype
list-type
functietype
tabeltype
nullable-type
primitieve-type: een van
any anynonnull binary date datetime datetimezone duration function list logical
none null number record table text time type
De primitieve namen zijn contextuele trefwoorden die alleen worden herkend in een typecontext . Het gebruik van haakjes in een typecontext verplaatst de grammatica terug naar een reguliere expressiecontext, waarbij het gebruik van het trefwoord van het type moet worden teruggezet naar een typecontext. Als u bijvoorbeeld een functie wilt aanroepen in een typecontext , kunnen haakjes worden gebruikt:
type nullable ( Type.ForList({type number}) )
// type nullable {number}
Haakjes kunnen ook worden gebruikt voor toegang tot een variabele waarvan de naam botst met een primitieve-typenaam :
let record = type [ A = any ] in type {(record)}
// type {[ A = any ]}
In het volgende voorbeeld wordt een type gedefinieerd dat een lijst met getallen classificeert:
type { number }
Op dezelfde manier definieert het volgende voorbeeld een aangepast type dat records classificeert met verplichte velden met de naam X
en Y
waarvan de waarden getallen zijn:
type [ X = number, Y = number ]
Het toegeschreven type van een waarde wordt verkregen met behulp van de standaardbibliotheekfunctie Value.Type, zoals wordt weergegeven in de volgende voorbeelden:
Value.Type( 2 ) // type number
Value.Type( {2} ) // type list
Value.Type( [ X = 1, Y = 2 ] ) // type record
De is
operator wordt gebruikt om te bepalen of het type van een waarde compatibel is met een bepaald type, zoals wordt weergegeven in de volgende voorbeelden:
1 is number // true
1 is text // false
{2} is list // true
De as
operator controleert of de waarde compatibel is met het opgegeven type en genereert een fout als dat niet het is. Anders wordt de oorspronkelijke waarde geretourneerd.
Value.Type( 1 as number ) // type number
{2} as text // error, type mismatch
Houd er rekening mee dat de is
operators as
alleen nullable primitieve typen accepteren als de juiste operand. M biedt geen middelen om waarden te controleren op overeenstemming met aangepaste typen.
Een type X
is compatibel met een type Y
als en alleen als alle waarden die voldoen X
aan ook voldoen.Y
Alle typen zijn compatibel met type any
en geen typen (maar none
zelf) zijn compatibel met het type none
. In de volgende grafiek ziet u de compatibiliteitsrelatie. (Typecompatibiliteit is reflexief en transitief. Het vormt een lattice met type any
als de bovenkant en het type none
als de laagste waarde.) De namen van abstracte typen worden cursief ingesteld.
De volgende operators worden gedefinieerd voor typewaarden:
Operator | Resultaat |
---|---|
x = y |
Equal |
x <> y |
Not equal |
x ?? y |
Coalesce |
Het systeemeigen type van typewaarden is het intrinsieke type type
.
Typen in de M-taal vormen een niet-aaneengesloten hiërarchie die is geroot op type any
. Dit is het type dat alle waarden classificeert. Elke M-waarde voldoet aan precies één primitief subtype van any
. De gesloten set primitieve typen die zijn afgeleid van het type any
zijn als volgt:
-
type null
, waarmee de null-waarde wordt classificeerd. -
type logical
, waarmee de waarden waar en onwaar worden geclassificeerd. -
type number
, waarmee getalwaarden worden geclassificeerd. -
type time
, waarmee tijdwaarden worden geclassificeerd. -
type date
, waarmee datumwaarden worden geclassificeerd. -
type datetime
, waarmee datum/tijd-waarden worden geclassificeerd. -
type datetimezone
, waarmee datum/tijdzone-waarden worden geclassificeerd. -
type duration
, waarmee duurwaarden worden geclassificeerd. -
type text
, waarmee tekstwaarden worden geclassificeerd. -
type binary
, waarmee binaire waarden worden geclassificeerd. -
type type
, waarmee typewaarden worden geclassificeerd. -
type list
, waarmee lijstwaarden worden geclassificeerd. -
type record
, waarmee recordwaarden worden geclassificeerd. -
type table
, waarmee tabelwaarden worden geclassificeerd. -
type function
, waarmee functiewaarden worden geclassificeerd. -
type anynonnull
, waarmee alle waarden worden geclassificeerd, met uitzondering van null. -
type none
, waarmee geen waarden worden geclassificeerd.
Het type any
is abstract, classificeert alle waarden in M en alle typen in M zijn compatibel met any
. Variabelen van het type any
kunnen worden gebonden aan alle mogelijke waarden. Aangezien any
abstract is, kan het niet worden toegeschreven aan waarden, dat wil gezegd, geen waarde rechtstreeks van het type any
is.
Elke waarde die een lijst is, voldoet aan het intrinsieke type list
, waardoor geen beperkingen gelden voor de items binnen een lijstwaarde.
list-type:
{
itemtype}
itemtype:
type
Het resultaat van het evalueren van een lijsttype is een lijsttypewaarde waarvan het basistype is list
.
In de volgende voorbeelden ziet u de syntaxis voor het declareren van homogene lijsttypen:
type { number } // list of numbers type
{ record } // list of records type
{{ text }} // list of lists of text values
Een waarde voldoet aan een lijsttype als de waarde een lijst is en elk item in die lijstwaarde voldoet aan het itemtype van het lijsttype.
Het itemtype van een lijsttype geeft een afhankelijkheid aan: alle items van een conforme lijst voldoen aan het itemtype.
Elke waarde die een record is, voldoet aan de intrinsieke typerecord, waardoor geen beperkingen gelden voor de veldnamen of -waarden binnen een recordwaarde. Een recordtypewaarde wordt gebruikt om de set geldige namen en de typen waarden te beperken die aan deze namen mogen worden gekoppeld.
recordtype:
[
open-record-marker]
[
opt voor field-specification-list]
[
field-specification-list , open-record-marker]
field-specification-list:
veldspecificatie
field-specification,
field-specification-list
veldspecificatie:
optional
opt field-name field-type-specificationopt
veldtypespecificatie:
=
veldtype
veldtype:
type
open-recordmarkering:
...
Het resultaat van het evalueren van een recordtype is een typewaarde waarvan het basistype is record
.
In de volgende voorbeelden ziet u de syntaxis voor het declareren van recordtypen:
type [ X = number, Y = number]
type [ Name = text, Age = number ]
type [ Title = text, optional Description = text ]
type [ Name = text, ... ]
Recordtypen worden standaard gesloten , wat betekent dat extra velden die niet aanwezig zijn in de veldspecificatielijst , niet mogen aanwezig zijn in het voldoen aan waarden. Als u de openrecordmarkering in het recordtype opneemt, wordt opgegeven dat het type geopend is, waardoor velden die niet aanwezig zijn in de lijst met veldspecificaties, zijn toe te staan. De volgende twee expressies zijn equivalent:
type record // primitive type classifying all records
type [ ... ] // custom type classifying all records
Een waarde voldoet aan een recordtype als de waarde een record is en elke veldspecificatie in het recordtype is voldaan. Aan een veldspecificatie wordt voldaan als een van de volgende waar is:
Er bestaat een veldnaam die overeenkomt met de id van de specificatie in de record en de bijbehorende waarde voldoet aan het type van de specificatie
De specificatie is gemarkeerd als optioneel en er wordt geen overeenkomende veldnaam gevonden in de record
Een conforme waarde kan veldnamen bevatten die niet worden vermeld in de lijst met veldspecificaties als en alleen als het recordtype is geopend.
Elke functiewaarde voldoet aan het primitieve type function
, waarbij geen beperkingen worden ingesteld voor de typen formele parameters van de functie of de retourwaarde van de functie. Een aangepaste functietypewaarde wordt gebruikt om typebeperkingen te plaatsen voor de handtekeningen van conforme functiewaarden.
functietype:
function (
parameter-specification-listopt)
function-return-type
parameter-specification-list:
required-parameter-specification-list
required-parameter-specification-list,
optional-parameter-specification-list
optional-parameter-specification-list
required-parameter-specification-list:
required-parameter-specification
required-parameter-specification,
required-parameter-specification-list
required-parameter-specification:
parameterspecificatie
optional-parameter-specification-list:
optioneel-parameterspecificatie
optional-parameter-specification optional-parameter-specification-list,
optional-parameter-specification:
optional
parameterspecificatie
parameterspecificatie:
parameter-naam parameter-type
function-return-type:
assertion
bewering:
as
nullable-primitive-type
Het resultaat van het evalueren van een functietype is een typewaarde waarvan het basistype is function
.
In de volgende voorbeelden ziet u de syntaxis voor het declareren van functietypen:
type function (x as text) as number
type function (y as number, optional z as text) as any
Een functiewaarde voldoet aan een functietype als het retourtype van de functiewaarde compatibel is met het retourtype van het functietype en elke parameterspecificatie van het functietype compatibel is met de positioneel overeenkomende formele parameter van de functie. Een parameterspecificatie is compatibel met een formele parameter als het opgegeven parametertype compatibel is met het type van de formele parameter en de parameterspecificatie is optioneel als de formele parameter optioneel is.
Formele parameternamen worden genegeerd voor het bepalen van de conformiteit van het functietype.
Als u een parameter opgeeft als optioneel, kan het type impliciet null worden. De volgende typen identieke functies maken:
type function (optional x as text) as any
type function (optional x as nullable text) as any
Een tabeltypewaarde wordt gebruikt om de structuur van een tabelwaarde te definiëren.
tabeltype:
table
rijtype
rijtype:
[
opt voor field-specification-list]
Het resultaat van het evalueren van een tabeltype is een typewaarde waarvan het basistype is table
.
Het rijtype van een tabel geeft de kolomnamen en kolomtypen van de tabel op als een gesloten recordtype. Zodat alle tabelwaarden voldoen aan het type table
, is het rijtype van record
het type (het lege geopende recordtype). Het type tabel is dus abstract omdat geen tabelwaarde het rijtype van het type kan hebben table
(maar alle tabelwaarden hebben een rijtype dat compatibel is met het rijtype van het type table
). In het volgende voorbeeld ziet u de constructie van een tabeltype:
type table [A = text, B = number, C = binary]
// a table type with three columns named A, B, and C
// of column types text, number, and binary, respectively
Een tabeltypewaarde bevat ook de definitie van de sleutels van een tabelwaarde. Een sleutel is een set kolomnamen. Maximaal één sleutel kan worden aangewezen als de primaire sleutel van de tabel. (In M hebben tabelsleutels geen semantische betekenis. Het is echter gebruikelijk dat externe gegevensbronnen, zoals databases of OData-feeds, sleutels over tabellen definiëren. Power Query gebruikt belangrijke informatie om de prestaties van geavanceerde functionaliteit te verbeteren, zoals joinbewerkingen tussen meerdere bronnen.)
De standaardbibliotheekfuncties Type.TableKeys
en Type.AddTableKey
Type.ReplaceTableKeys
kunnen worden gebruikt om de sleutels van een tabeltype te verkrijgen, een sleutel toe te voegen aan een tabeltype en alle sleutels van een tabeltype te vervangen.
Type.AddTableKey(tableType, {"A", "B"}, false)
// add a non-primary key that combines values from columns A and B
Type.ReplaceTableKeys(tableType, {})
// returns type value with all keys removed
Voor elke type T
, kan een nullable variant worden afgeleid met behulp van nullable-type:
nullable-type:
nullable
type
Het resultaat is een abstract type dat waarden van het type T of de waarde null
toestaat.
42 is nullable number // true null is
nullable number // true
Ascriptie van type nullable
T vermindert tot beschrijving van type null
of type
T. (Zoals u weet, zijn null-typen abstract en kan er geen waarde rechtstreeks van abstract type zijn.)
Value.Type(42 as nullable number) // type number
Value.Type(null as nullable number) // type null
De standaardbibliotheekfuncties Type.IsNullable
en Type.NonNullable
kunnen worden gebruikt om een type te testen op nullbaarheid en om null-functionaliteit van een type te verwijderen.
De volgende bewaring (voor elke type T
):
-
type T
is compatibel mettype nullable T
-
Type.NonNullable(type T)
is compatibel mettype T
Hier volgen paarsgewijze equivalenten (voor elke):type T
type nullable any
any
Type.NonNullable(type any)
type anynonnull
type nullable none
type null
Type.NonNullable(type null)
type none
type nullable nullable T
type nullable T
Type.NonNullable(Type.NonNullable(type T))
Type.NonNullable(type T)
Type.NonNullable(type nullable T)
Type.NonNullable(type T)
type nullable (Type.NonNullable(type T))
type nullable T
Het getscribeerde type van een waarde is het type waaraan een waarde wordt gedeclareerd om te voldoen.
Een waarde kan een type worden toegekend met behulp van de bibliotheekfunctie Value.ReplaceType
. Deze functie retourneert een nieuwe waarde met het type dat is toegekend of genereert een fout als het nieuwe type niet compatibel is met de waarde.
Wanneer een waarde wordt toegekend aan een type, vindt er slechts een beperkte nalevingscontrole plaats:
- Het type dat wordt toegekend, moet niet-abstract, niet nullable zijn en compatibel zijn met het intrinsieke (systeemeigen) primitieve type van de waarde.
- Wanneer een aangepast type dat structuur definieert, moet deze overeenkomen met de structuur van de waarde.
- Voor records: het type moet worden gesloten, moet hetzelfde aantal velden definiëren als de waarde en mag geen optionele velden bevatten. (De veldnamen en veldtypen van het type vervangen die momenteel aan de record zijn gekoppeld. Bestaande veldwaarden worden echter niet gecontroleerd op basis van de nieuwe veldtypen.)
- Voor tabellen: Het type moet hetzelfde aantal kolommen definiëren als de waarde. (De kolomnamen en kolomtypen van het type vervangen de kolomtypen die momenteel aan de tabel zijn gekoppeld. Bestaande kolomwaarden worden echter niet gecontroleerd op basis van de nieuwe kolomtypen.)
- Voor functies: Het type moet hetzelfde aantal vereiste parameters definiëren, evenals hetzelfde aantal optionele parameters als de waarde. (De parameter van het type en retourneert asserties, evenals de parameternamen, vervangen die zijn gekoppeld aan het huidige type van de functiewaarde. De nieuwe asserties hebben echter geen effect op het werkelijke gedrag van de functie.)
- Voor lijsten: De waarde moet een lijst zijn. (Bestaande lijstitems worden echter niet gecontroleerd op het nieuwe itemtype.)
Bibliotheekfuncties kunnen ervoor kiezen om complexe typen te berekenen en toe te schrijven aan resultaten op basis van de getscribeerde typen van de invoerwaarden.
Het toegeschreven type van een waarde kan worden verkregen met behulp van de bibliotheekfunctie Value.Type
. Voorbeeld:
Value.Type( Value.ReplaceType( {1}, type {number} )
// type {number}
De gelijkwaardigheid van het type is niet gedefinieerd in M. Een M-implementatie kan er eventueel voor kiezen om eigen regels te gebruiken om gelijkheidsvergelijkingen tussen typewaarden uit te voeren. Als u twee typewaarden voor gelijkheid vergelijkt, moet worden geëvalueerd true
of deze identiek worden geacht door de implementatie en false
anders. In beide gevallen moet het geretourneerde antwoord consistent zijn als dezelfde twee waarden herhaaldelijk worden vergeleken. Houd er rekening mee dat het vergelijken van een aantal identieke typewaarden (zoals (type text) = (type text)
) binnen een bepaalde implementatie mogelijk niet retourneert true
, terwijl andere (zoals (type [a = text]) = (type [a = text])
) niet worden vergeleken.
Compatibiliteit tussen een bepaald type en een primitief type dat null kan worden gebruikt, kan worden bepaald met behulp van de bibliotheekfunctie Type.Is
, die een willekeurige typewaarde accepteert als eerste en een nullable primitieve typewaarde als het tweede argument:
Type.Is(type text, type nullable text) // true
Type.Is(type nullable text, type text) // false
Type.Is(type number, type text) // false
Type.Is(type [a=any], type record) // true
Type.Is(type [a=any], type list) // false
Er is geen ondersteuning in M voor het bepalen van de compatibiliteit van een bepaald type met een aangepast type.
De standaardbibliotheek bevat een verzameling functies om de definiërende kenmerken van een aangepast type te extraheren, zodat specifieke compatibiliteitstests kunnen worden geïmplementeerd als M-expressies. Hieronder ziet u enkele voorbeelden; raadpleeg de M-bibliotheekspecificatie voor volledige details.
Type.ListItem( type {number} )
// type number
Type.NonNullable( type nullable text )
// type text
Type.RecordFields( type [A=text, B=time] )
// [ A = [Type = type text, Optional = false],
// B = [Type = type time, Optional = false] ]
Type.TableRow( type table [X=number, Y=date] )
// type [X = number, Y = date]
Type.FunctionParameters(
type function (x as number, optional y as text) as number)
// [ x = type number, y = type nullable text ]
Type.FunctionRequiredParameters(
type function (x as number, optional y as text) as number)
// 1
Type.FunctionReturn(
type function (x as number, optional y as text) as number)
// type number