種類

"型値" はその他の値を "分類する" 値です。 型で分類される値は、その型に "準拠する" とされます。 M 型システムは、次の種類の型で構成されています。

  • プリミティブ型。これはプリミティブ値 (binarydatedatetimedatetimezonedurationlistlogicalnullnumberrecordtexttimetype) を分類するものであり、また、これにはさまざまな抽象型 (functiontableanyanynonnullnone) が含まれます

  • レコード型。これはフィールドの名前や値の型に基づいてレコード値を分類するものです

  • リスト型。これは単一項目の基本型を利用して一覧を分類するものです

  • 関数型。これはそのパラメーターの型に基づいて関数値を分類し、値を返すものです

  • テーブル型。これは列の名前、列の型、キーに基づいてテーブル値を分類するものです

  • null 許容型。これは、基本型によって分類されるすべての値に加え、値 null を分類するものです

  • タイプ型。これは型である値を分類するものです

"プリミティブ型" のセットには、プリミティブ値の型、さまざまな "抽象型"、値を一意に分類しない型 (functiontableanyanynonnullnone) が含まれます。 関数値はすべて抽象型 function に準拠し、テーブル値はすべて抽象型 table に準拠し、すべての値は抽象型 any に準拠し、非 null 値はすべて抽象型 anynonnull に準拠し、値なしは抽象型 none に準拠します。 式の型が none であれば、エラーが出るか、失敗となり、強制終了します。型 none に準拠する値が生成されないためです。 プリミティブ型の functiontable は抽象です。それぞれ、直接的にその型になる関数やテーブルがないからです。 プリミティブ型の recordlist は抽象ではありません。それぞれ、フィールドが定義されていないオープン レコードと型 any の一覧を表すためです。

プリミティブ型の閉集合に属さないすべての型とその null 許容の片割れは "カスタム型" と総称されます。 カスタム型は type-expression を使用して記述できます。

type-expression:
      primary-expression

      typeprimary-type
の型:
      primary-expression
      primary-type
primary-type:
      primitive-type
      record-type
      list-type
      function-type
      table-type
      nullable-type
primitive-type:
次のいずれか
      any anynonnull binary date datetime datetimezone duration function list logical
      none null number record table text time type

"primitive-type" 名は、"" コンテキストでのみ認識される "コンテキスト キーワード" です。 "" コンテキストで括弧を使用すると、文法が通常の式コンテキストに戻るため、型コンテキストに戻るには、型キーワードを使用する必要があります。 たとえば、"" コンテキストで関数を呼び出すには、次のように括弧を利用できます。

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

括弧は、"primitive-type" 名と名前が競合する変数にアクセスする目的でも利用できます。

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

次の例では、数字の一覧を分類する型が定義されます。

type { number }

同様に、次の例では、名前が XY で、値が数字の必須フィールドによりレコードを分類するカスタム型が定義されます。

type [ X = number, Y = number ]

値の指定の型は、次の例のように、標準ライブラリ関数 Value.Type によって取得されます。

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

is 演算子は、次の例のように、値の型と指定の型の間に互換性があるか判断する目的で使用されます。

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

as 演算子では、値と指定の型の間に互換性があるかどうかが確認されます。互換性がない場合、エラーが出ます。 互換性があれば、元の値が返されます。

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

演算子の isas では、適切なオペランドとして null 許容プリミティブ型のみが受け取られます。 M には、値がカスタム型に準拠するか確認する手段がありません。

X は、X に準拠する値がすべて Y にも準拠する場合にのみ、型 Y と "互換" します。 すべての型が型 any と互換性があり、型 none と互換性のある型はありません (ただし、none 自体を除く)。 互換性の関係を示したのが次のグラフです。 (型の互換性は反射的であり、推移的です。型 any を一番上の値、型 none を一番下の値とする格子を形成します。) 抽象型の名前は "斜体" になっています。

型の互換性

型値には次の演算子が定義されています。

演算子 結果
x = y 等しい
x <> y 等しくない
x ?? y Coalesce

型値のネイティブ型は組み込み型の type です。

プリミティブ型

M 言語の型は、すべての値を分類する型である型 any をルートとする独立階層を形成します。 あるゆる M 値は、any の亜類型のうちの 1 つだけに順守します。 型 any から派生するプリミティブ型の閉集合は次のようになります。

  • type null。null 値を分類します。
  • type logical。true 値と false 値を分類します。
  • type number。数値を分類します。
  • type time。時間値を分類します。
  • type date。日付値を分類します。
  • type datetime。datetime 値を分類します。
  • type datetimezone。datetimezone 値を分類します。
  • type duration。期間値を分類します。
  • type text。テキスト値を分類します。
  • type binary。バイナリ値を分類します。
  • type type。型値を分類します。
  • type list。リスト値を分類します。
  • type record。レコード値を分類します。
  • type table。テーブル値を分類します。
  • type function。関数値を分類します。
  • type anynonnull。null を除くすべての値を分類します。
  • type none。何の値も分類しません。

any 型

any は抽象型であり、M のすべての値を分類します。M の型はすべて any と互換性があります。 型 any の変数は使用可能なすべての値にバインドできます。 any は抽象型であるため、値に指定できません。つまり、直接的に型 any になる値はありません。

リスト型

一覧である値はすべて、組み込み型 list に準拠し、一覧値内の項目には何の制限も課されません。

list-type:
      {item-type}
item-type:
      型

"list-type" を評価すると、基本型が list の "リスト型値" になります。

次の例からは、同種のリスト型を宣言するための構文がわかります。

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

値は、その値が一覧であり、その一覧値の各項目がリスト型の項目の型に準拠する場合、リスト型に準拠します。

リスト型の項目の型は境界を示します。準拠する一覧のすべての項目は項目の型に準拠します。

レコード型

レコードである値はすべて、組み込み型レコードに準拠し、レコード値内のフィールドの名前や値には何の制限も課されません。 "record-type value" は、一連の有効な名前と、その名前に関連付けられる値の型を制限する目的で使用されます。

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

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

      =field-type
field-type:
      型
open-record-marker:

      ...

"record-type" を評価すると、基本型が record の型値になります。

次の例からは、レコード型を宣言するための構文がわかります。

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

レコード型は既定で "" です。つまり、"fieldspecification-list" にない追加フィールドを、準拠する値に入れることはできません。 レコード型に "openrecord-marker" を入れると、型が "" であると宣言され、フィールド仕様一覧にないフィールドが許可されます。 次の 2 つの式は同等です。

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

値は、その値がレコードであり、レコード型の各フィールド仕様が満たされる場合、レコード型に準拠します。 フィールド仕様は、次のいずれかが当てはまる場合に満たされます。

  • 仕様の識別子に一致するフィールド名はレコードの中にあり、関連値は仕様の型に準拠します。

  • 仕様には省略可能の印が付き、該当するフィールド名はレコード内で見つかります。

準拠する値には、レコード型が開の場合にのみ、フィールド仕様一覧にないフィールド名が含まれることがあります。

関数型

関数値はプリミティブ型 function に準拠します。この型では、関数の仮パラメーターや関数の戻り値の型に制限が課されません。 カスタム "function-type 値" は、準拠する関数値のシグネチャに型制限を課す目的で使用されます。

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

      optionalparameter-specification
parameter-specification:
      parameter-name parameter-type
function-return-type:
      assertion
assertion:

      asnullable-primitive-type

"function-type" を評価すると、基本型が function の型値になります。

次の例からは、関数型を宣言するための構文がわかります。

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

関数値は、その関数値の戻り型が関数型の戻り型と互換性があり、関数の各パラメーター仕様が関数の位置的に該当する仮パラメーターと互換性がある場合、関数型に準拠します。 パラメーター仕様は、指定の "parameter-type" 型が仮パラメーターの型と互換性がある場合にその仮パラメーターと互換性があります。パラメーター仕様は、仮パラメーターが省略可能の場合は省略可能です。

仮パラメーターの名前は、関数型の準拠を判断するという目的では無視されます。

パラメーターを省略可能 (optional) として指定すると、その型は暗黙的に null 許容になります。 次では同じ関数型が作成されます。

type function (optional x as text) as any
type function (optional x as nullable text) as any

テーブル型

"table-type 値" は、テーブル値の構造を定義する目的で使用されます。

table-type:
      tablerow-type
row-type:

      [field-specification-listopt]

"table-type" を評価すると、基本型が table の型値になります。

テーブルの "行型" により、テーブルの列の名前と列の種類が閉じられたレコード型として指定されます。 そのため、テーブル値はすべて型 table に準拠し、その行型は型 record です (空の開いたレコード型)。 そのため、型 table の行型が入るテーブル値がなく (ただし、型 table の行型と互換性がある行型がすべてのテーブル値に与えられる)、型テーブルは抽象型になります。 次の例では、テーブル形の構成を確認できます。

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

table-type 値には、テーブル値の "キー" の定義も含まれます。 キーは一連の列名です。 テーブルの "主キー" としてキーを 1 つだけ指名できます。 (M 内では、テーブル キーに意味がありません。ただし、データベースや OData フィードなどの外部データ ソースでテーブルのキーを定義することが一般的です。Power Query では、ソース間の結合操作など、高度な機能のパフォーマンスを改善する目的でキー情報が使用されます。)

標準ライブラリ関数 Type.TableKeysType.AddTableKeyType.ReplaceTableKeys を使用してそれぞれ、テーブル型のキーを取得し、テーブル型のキーを追加し、テーブル型の全キーを置換します。

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

null 許容型

type T には、null 許容バリアントは nullable-type を利用して派生できます。

nullable-type:
      nullabletype

結果的に、抽象型で型 T または値 null が許可されます。

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

type nullableT の帰属により type null または typeT の帰属に降格します。(null 許容型は抽象型であり、直接的に抽象型にできる値はありません。)

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

標準ライブラリ関数の Type.IsNullableType.NonNullable は、型の null 許容性をテストし、型から null 許容性を取り除く目的で利用できます。

(あらゆる type T で) 次が当てはまります。

  • type Ttype nullable T に互換性があります
  • Type.NonNullable(type T)type T に互換性があります

(あるゆる 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

値の指定の型

値の "指定の型" は、値が準拠を "宣言する" 型です。

値には、ライブラリ関数 Value.ReplaceType を使用する型を指定することができます。 この関数は、指定した型の新しい値を返しますが、新しい型が値と互換性がない場合にはエラーを返します。

値に型が指定されるとき、限定的な準拠確認のみが行われます。

  • 指定する型は、値の組み込み (ネイティブ) プリミティブ型と互換性を持つ、非抽象かつ null 非許容の型とする必要があります。
  • 構造を定義するカスタム型を指定する場合は、それと値の構造とを一致させる必要があります。
    • レコードの場合: 型は閉じる必要があります。型では値と同じ数のフィールドを定義する必要があります。型に省略可能なフィールドを含めてはなりません (型のフィールド名とフィールド型は、現在レコードに関連付けられているものに置き換えられます。ただし、既存のフィールド値が、新しいフィールド型と照らし合わせてチェックされることはありません)。
    • テーブルの場合: 型では、値と同じ数の列を定義する必要があります (型の列名と列型は、現在テーブルに関連付けられているものに置き換えられます。ただし、既存の列値が、新しい列型と照らし合わせてチェックされることはありません)。
    • 関数の場合: 型では、値と同じ数の必須パラメーターと、値と同じ数の省略可能なパラメーターを定義する必要があります (型のパラメーターおよび戻り値アサーションと、そのパラメーター名は、関数値の現在の型に関連付けられているものに置き換えられます。ただし、新しいアサーションが関数の実際の動作に影響することはありません)。
    • リストの場合: 値をリストとする必要があります (ただし、既存のリスト項目が、新しい項目型と照らし合わせてチェックされることはありません)。

ライブラリ関数では、入力された値に指定されている型に基づき、複雑な型を計算し、それを結果に割り当てることがあります。

値に指定されている型は、ライブラリ関数 Value.Type で取得できることがあります。 例:

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

型の等価性と互換性

型の等価性は M では定義されていません。M 実装では、必要に応じて、独自の規則を使用して型値間の等価比較を実行することを選択できます。 2 つの型値の等価性の比較は、実装で同一と見なされる場合は true と評価され、それ以外の場合は false と評価されます。 どちらの場合も、同じ 2 つの値を繰り返し比較する場合、返される応答は一貫している必要があります。 特定の実装内で、一部の同一の型値 ((type text) = (type text) など) を比較すると true が返される場合があり、他 ((type [a = text]) = (type [a = text]) など) を比較しても返されない場合があることに注意してください。

指定の型と null 許容プリミティブ型の間の互換性は、ライブラリ関数 Type.Is を利用して決定できます。この関数では、最初の引数として任意の型が受け取られ、2 番目の引数として null 許容プリミティブ型が受け取られます。

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

M では、指定の型とカスタム型の互換性を判断することはできません。

この標準ライブラリには、定義となる特性をカスタム型から抽出する関数のコレクションが含まれます。そのため、特定の互換性テストを M 式として実装できます。 下に例をいくつか挙げます。詳細については、M ライブラリの仕様をご覧ください。

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