種類
"型値" はその他の値を "分類する" 値です。 型で分類される値は、その型に "準拠する" とされます。 M 型システムは、次の種類の型で構成されています。
プリミティブ型。これはプリミティブ値 (
binary
、date
、datetime
、datetimezone
、duration
、list
、logical
、null
、number
、record
、text
、time
、type
) を分類するものであり、また、これにはさまざまな抽象型 (function
、table
、any
、anynonnull
、none
) が含まれますレコード型。これはフィールドの名前や値の型に基づいてレコード値を分類するものです
リスト型。これは単一項目の基本型を利用して一覧を分類するものです
関数型。これはそのパラメーターの型に基づいて関数値を分類し、値を返すものです
テーブル型。これは列の名前、列の型、キーに基づいてテーブル値を分類するものです
null 許容型。これは、基本型によって分類されるすべての値に加え、値 null を分類するものです
タイプ型。これは型である値を分類するものです
"プリミティブ型" のセットには、プリミティブ値の型、さまざまな "抽象型"、値を一意に分類しない型 (function
、table
、any
、anynonnull
、none
) が含まれます。 関数値はすべて抽象型 function
に準拠し、テーブル値はすべて抽象型 table
に準拠し、すべての値は抽象型 any
に準拠し、非 null 値はすべて抽象型 anynonnull
に準拠し、値なしは抽象型 none
に準拠します。 式の型が none
であれば、エラーが出るか、失敗となり、強制終了します。型 none
に準拠する値が生成されないためです。 プリミティブ型の function
と table
は抽象です。それぞれ、直接的にその型になる関数やテーブルがないからです。 プリミティブ型の record
と list
は抽象ではありません。それぞれ、フィールドが定義されていないオープン レコードと型 any の一覧を表すためです。
プリミティブ型の閉集合に属さないすべての型とその null 許容の片割れは "カスタム型" と総称されます。 カスタム型は type-expression
を使用して記述できます。
type-expression:
primary-expression
type
primary-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 }
同様に、次の例では、名前が X
と Y
で、値が数字の必須フィールドによりレコードを分類するカスタム型が定義されます。
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
演算子の is
と as
では、適切なオペランドとして 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:
optional
opt 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:
optional
parameter-specification
parameter-specification:
parameter-name parameter-type
function-return-type:
assertion
assertion:
as
nullable-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:
table
row-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.TableKeys
、Type.AddTableKey
、Type.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:
nullable
type
結果的に、抽象型で型 T または値 null
が許可されます。
42 is nullable number // true null is
nullable number // true
type nullable
T の帰属により type null
または type
T の帰属に降格します。(null 許容型は抽象型であり、直接的に抽象型にできる値はありません。)
Value.Type(42 as nullable number) // type number
Value.Type(null as nullable number) // type null
標準ライブラリ関数の Type.IsNullable
と Type.NonNullable
は、型の null 許容性をテストし、型から null 許容性を取り除く目的で利用できます。
(あらゆる type T
で) 次が当てはまります。
type T
とtype 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