Typer

Ett typvärde är ett värde som klassificerar andra värden. Ett värde som klassificeras av en typ sägs överensstämma med den typen. M-typsystemet består av följande typer:

  • Primitiva typer, som klassificerar primitiva värden (binary, date, datetime, datetimezone, duration, list, logical, null, number, record, text, time, type) och även innehåller ett antal abstrakta typer (function, table, any och none)

  • Posttyper, som klassificerar postvärden baserat på fältnamn och värdetyper

  • Listtyper, som klassificerar listor med hjälp av en enda objektbastyp

  • Funktionstyper, som klassificerar funktionsvärden baserat på typerna av deras parametrar och returvärden

  • Tabelltyper, som klassificerar tabellvärden baserat på kolumnnamn, kolumntyper och nycklar

  • Nullbara typer, som klassificerar värdet null förutom alla värden som klassificeras av en bastyp

  • Typtyper, som klassificerar värden som är typer

Uppsättningen primitiva typer innehåller typerna av primitiva värden, ett antal abstrakta typer, typer som inte unikt klassificerar några värden: function, table, any och none. Alla funktionsvärden stämmer överens med den abstrakta typen function, alla tabellvärden med den abstrakta typen table, alla värden med den abstrakta typen anyoch inga värden med den abstrakta typen none. Ett uttryck av typen none måste generera ett fel eller så går det inte att avsluta eftersom inget värde kunde skapas som överensstämmer med typ none. Observera att de primitiva typerna function och table är abstrakta eftersom ingen funktion eller tabell direkt är av någon av dessa respektive typer. De primitiva typerna record och list är icke-abstrakta eftersom de representerar en öppen post utan definierade fält respektive en lista av typen alla.

Alla typer som inte är medlemmar i den stängda uppsättningen primitiva typer kallas gemensamt för anpassade typer. Anpassade typer kan skrivas med hjälp av en type-expression:

type-expression:
      primary-expression

      typeprimär typ
Typ:
      parenthesized-expression
      primär typ
primär typ:
      primitiv typ
      posttyp
      listtyp
      funktionstyp
      tabelltyp
      nullable-type
primitive-type:
en av
      any binary date datetime datetimezone duration function list logical
      none null number record table text time type

primitive-type-namnen är sammanhangsbaserade nyckelord som enbart identifieras i en type-kontext. Användningen av parenteser i en type-kontext flyttar tillbaka grammatiken till kontexten reguljärt uttryck, vilket kräver att type-nyckelordet används för att gå tillbaka till en type-kontext. Om du till exempel vill anropa en funktion i en type-kontext kan parenteser användas:

type nullable ( Type.ForList({type number}) )   
// type nullable {number}

Parenteser kan också användas för att få åtkomst till en variabel vars namn krockar med ett primitive-type-namn:

let  record = type [ A = any ]  in  type {(record)} 
// type {[ A = any ]}

I följande exempel definieras en typ som klassificerar en lista med tal:

type { number }

På samma sätt definierar följande exempel en anpassad typ som klassificerar poster med obligatoriska fält med namnen X och Y vars värden är tal:

type [ X = number, Y = number ]

Den tilldelade typen av ett värde hämtas med hjälp av standardbiblioteksfunktionen Value.Type, som du ser i följande exempel:

Value.Type( 2 )                 // type number 
Value.Type( {2} )               // type list 
Value.Type( [ X = 1, Y = 2 ] )  // type record

Operatorn is används för att avgöra om ett värdes typ är kompatibel med en angiven typ, som du ser i följande exempel:

1 is number          // true 
1 is text            // false 
{2} is list          // true

Operatorn as kontrollerar om värdet är kompatibelt med den aktuella typen och genererar ett fel om det inte är det. Annars returneras det ursprungliga värdet.

Value.Type( 1 as number )   // type number 
{2} as text                 // error, type mismatch

Observera att operatorerna is och as endast accepterar primitiva typer som höger operand. M ger inte möjlighet att kontrollera värden för överensstämmelse med anpassade typer.

En X-typ är kompatibel med en Y-typ om och bara om alla värden som överensstämmer med X också överensstämmer med Y. Alla typer är kompatibla med typen any och inga typer (utom none i sig själv) är kompatibla med typen none. Följande diagram visar kompatibilitetsrelationen. (Typkompatibiliteten är reflexiv och transitiv. Den bildar ett gitter med typen any som överkant och skriver none som det nedre värdet.) Namnen på abstrakta typer anges i kursiv stil.

Typkompatibilitet

Följande operatorer har definierats för typvärden:

Operator Resultat
x = y Lika med
x <> y Inte lika med
x ?? y Coalesce

Den interna typen av typvärden är den inbyggda typen type.

Primitiva typer

Typerna i M-språket utgör en uppdelad hierarki som är rotad vid typ any, vilket är den typ som klassificerar alla värden. Alla M-värden motsvarar exakt en primitiv undertyp till any. Den stängda uppsättningen primitiva typer som härleds från typen any är följande:

  • type null, som klassificerar null-värdet.
  • type logical, som klassificerar värdena true och false.
  • type number, som klassificerar värdet number.
  • type time, som klassificerar värdet time.
  • type date, som klassificerar värdet date.
  • type datetime, som klassificerar värdet datetime.
  • type datetimezone, som klassificerar värdet datetimezone.
  • type duration, som klassificerar värdet duration.
  • type text, som klassificerar text-värden.
  • type binary, som klassificerar binary-värden.
  • type type, som klassificerar type-värden.
  • type list, som klassificerar list-värden.
  • type record, som klassificerar record-värden.
  • type table, som klassificerar tabellvärden.
  • type function, som klassificerar funktionsvärden.
  • type anynonnull, som klassificerar alla värden exklusive null. Den inbyggda typen none klassificerar inga värden.

Any-typen

Typen any är abstrakt, klassificerar alla värden i M, och alla typer i M är kompatibla med any. Variabler av typen any kan bindas till alla möjliga värden. Eftersom any är abstrakt kan det inte tillskrivas värden, det vill säga inget värde är direkt av typen any.

Listtyper

Alla värden som är en lista överensstämmer med den inbyggda typen list, som inte använder några begränsningar för objekten i ett list-värde.

list-type:
      {objekttyp}
objekttyp:
      typ

Resultatet av att utvärdera en list-type är ett listtypsvärde vars bastyp är list.

I följande exempel visas syntaxen för att deklarera homogena listtyper:

type { number }        // list of numbers type 
     { record }        // list of records type
     {{ text }}        // list of lists of text values

Ett värde överensstämmer med en listtyp om värdet är en lista och varje objekt i det listvärdet överensstämmer med listtypens objekttyp.

Objekttypen för en listtyp anger en bindning: alla objekt i en överensstämmande lista motsvarar objekttypen.

Posttyper

Alla värden som är en post överensstämmer med den inbyggda typposten, som inte använder några begränsningar för fältnamn eller värden i ett postvärde. Ett record-type-värde används för att begränsa uppsättningen giltiga namn samt vilka typer av värden som får associeras med dessa namn.

record-type:
      [open-record-marker]
      [field-specification-listopt]
      [field-specification-list , open-record-marker]
field-specification-list:
      fältspecifikation
      field-specification,field-specification-list
fältspecifikation:

      optionalopt field-name field-type-specificationopt
field-type-specification:

      =fälttyp
fälttyp:
      typ
open-record-marker:

      ...

Resultatet av att utvärdera en record-type är ett typvärde vars bastyp är record.

I följande exempel visas syntaxen för att deklarera posttyper:

type [ X = number, Y = number] 
type [ Name = text, Age = number ]
type [ Title = text, optional Description = text ] 
type [ Name = text, ... ]

Posttyper är stängda som standard, vilket innebär att ytterligare fält som inte finns i fieldspecification-list inte får finnas i överensstämmande värden. Genom att inkludera openrecord-marker i posttypen deklareras att typen ska vara öppen, vilket tillåter fält som inte finns i fältspecifikationslistan. Följande två uttryck är likvärdiga:

type record   // primitive type classifying all records 
type [ ... ]  // custom type classifying all records

Ett värde överensstämmer med en posttyp om värdet är en post och varje fältspecifikation i posttypen är uppfylld. En fältspecifikation är uppfylld om något av följande är sant:

  • Ett fältnamn som matchar specifikationens identifierare finns i posten och det associerade värdet överensstämmer med specifikationens typ

  • Specifikationen är markerad som valfri och inget motsvarande fältnamn hittas i posten

Ett överensstämmande värde kan innehålla fältnamn som inte visas i fältspecifikationslistan om och endast om posttypen är öppen.

Funktionstyper

Alla funktionsvärden överensstämmer med den primitiva typen function, som inte använder några begränsningar för typer av funktionens formella parametrar eller funktionens returvärde. Ett anpassat function-type-värde används för att placera typbegränsningar i signaturerna för överensstämmande funktionsvärden.

function-type:
      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:
      parameterspecifikation
optional-parameter-specification-list:
      optional-parameter-specification
      optional-parameter-specification
,optional-parameter-specification-list
optional-parameter-specification:

      optionalparameterspecifikation
parameterspecifikation:
      parameter-name parameter-type
function-return-type:
      Påstående
Påstående:

      asnullable-primitive-type

Resultatet av att utvärdera en function-type är ett typvärde vars bastyp är function.

I följande exempel visas syntaxen för att deklarera funktionstyper:

type function (x as text) as number 
type function (y as number, optional z as text) as any

Ett funktionsvärde överensstämmer med en funktionstyp om returtypen för funktionsvärdet är kompatibel med funktionstypens returtyp och varje parameterspecifikation för funktionstypen är kompatibel med den formella parameter i funktionen som är i motsvarande position. En parameterspecifikation är kompatibel med en formell parameter om angiven parameter-type-typ är kompatibel med typen för den formella parametern och parameterspecifikationen är valfri om den formella parametern är valfri.

Formella parameternamn ignoreras för att kunna fastställa funktionstypsöverensstämmelse.

Tabelltyper

Ett table-type-värde används för att definiera strukturen för ett tabellvärde.

table-type:
      tableradtyp
radtyp:

      [fältspecifikationslista]

Resultatet av att utvärdera en table-type är ett typvärde vars bastyp är table.

Radtypen för en tabell anger kolumnnamn och kolumntyper för tabellen som en stängd posttyp. Så att alla tabellvärden stämmer överens med typen table, och dess radtyp är av typen record (den tomma öppna posttypen). Typtabellen är således abstrakt eftersom inget tabellvärde kan ha radtypen för typen table (men alla tabellvärden har en radtyp som är kompatibel med radtypen för typen table). I följande exempel visas konstruktionen för en tabelltyp:

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

Ett table-type-värde innehåller också definitionen av tabellvärdets nycklar. En nyckel är en uppsättning kolumnnamn. Högst en nyckel kan anges som tabellens primärnyckel. (I M har tabellnycklar ingen semantisk betydelse. Det är dock vanligt att externa datakällor, till exempel databaser eller OData-feeds, definierar nycklar över tabeller. Power Query använder viktig information för att förbättra prestanda för avancerade funktioner, till exempel anslutningsåtgärder mellan källor.)

Standardbiblioteksfunktionerna Type.TableKeys, Type.AddTableKey och Type.ReplaceTableKeys kan användas för att hämta nycklar för en tabelltyp, lägga till en nyckel i en tabelltyp och ersätta alla nycklar för en tabelltyp.

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

Typer som kan ha värdet null

För alla type T kan en variant som kan ha värdet null härledas med hjälp av nullable-type:

nullable-type:
      nullabletype

Resultatet är en abstrakt typ som tillåter värden av typen T eller värdet null.

42 is nullable number             // true null is
nullable number                   // true

Ascription av type nullableT minskar till ascription av type null eller typeT. (Kom ihåg att typer som kan ha värdet null är abstrakta och att inget värde kan vara direkt av abstrakt typ.)

Value.Type(42 as nullable number)       // type number
Value.Type(null as nullable number)     // type null

Standardbiblioteksfunktionerna Type.IsNullable och Type.NonNullable kan användas för att testa en typ för nullbarhet och ta bort nullbarheten från en typ.

Följande undantag (för alla type T):

  • type T är kompatibel med type nullable T
  • Type.NonNullable(type T) är kompatibel med type T

Följande är parvis motsvariga (för alla 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

Tillskriven typ för ett värde

Ett värdes tillskrivna typ är den typ som ett värde är deklarerat att överensstämma med. När ett värde tillskrivs en typ sker endast en begränsad överensstämmelsekontroll. M utför inte överensstämmelsekontroll utöver en primitiv typ som kan ha värdet null. M-programförfattare som väljer att tillskriva värden med typdefinitioner som är mer komplexa än en nullbar primitiv typ måste se till att sådana värden överensstämmer med dessa typer.

Ett värde kan tillskrivas en typ med hjälp av biblioteksfunktionen Value.ReplaceType. Funktionen returnerar antingen ett nytt värde med typen som tillskrivs eller aktiverar ett fel om den nya typen inte är kompatibel med värdets ursprungliga primitiva typ. I synnerhet genererar funktionen ett fel när ett försök görs att tillskriva en abstrakt typ, till exempel any.

Biblioteksfunktioner kan välja att beräkna och tillskriva komplexa typer till resultat baserat på de tillskrivna typerna av indatavärden.

Den tillskrivna typen av ett värde kan hämtas med hjälp av biblioteksfunktionen Value.Type. Till exempel:

Value.Type( Value.ReplaceType( {1}, type {number} ) 
// type {number}

Typmotsvarighet och kompatibilitet

Typmotsvarighet definieras inte i M. Två valfria typer av värden som jämförs avseende motsvarighet kan eventuellt returnera true. Relationen mellan dessa två typer (oavsett true eller false) är dock alltid densamma.

Kompatibilitet mellan en specifik typ och en nullbar primitiv typ kan fastställas med hjälp av biblioteksfunktionen Type.Is, som accepterar ett godtyckligt typvärde som det första argumentet och ett nullbart primitivt typvärde som det andra argumentet:

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

Det finns inget stöd i M för att fastställa kompatibiliteten för en specifik typ med en anpassad typ.

Standardbiblioteket innehåller en samling funktioner för att extrahera de definierade egenskaperna från en anpassad typ, så särskilda kompatibilitetstest kan implementeras som M-uttryck. Nedan visas några exempel. Se specifikationen för M-biblioteket för fullständig information.

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