演算子の動作

このセクションでは、さまざまな M 演算子の動作を定義します。

演算子の優先順位

式に複数の演算子が含まれている場合、演算子の "優先順位" によって、個々の演算子を評価する順序が制御されます。 たとえば、式 x + y * zx + (y * z) として評価されます。これは、演算子 * の優先順位が 2 項演算子 + よりも高いためです。 演算子の優先順位は、関連付けられている文法プロダクションの定義によって決定されます。 たとえば、+ 演算子または - 演算子で区切られた一連の "乗除式" で構成された "加減式" で、+ 演算子と - 演算子の優先順位は * 演算子と / 演算子より低くなります。

parenthesized-expression プロダクションを使用すると、既定の優先順位を変更できます。

parenthesized-expression:
      (expression)

例:

1 + 2 * 3       // 7 
(1 + 2) * 3     // 9

次の表に、M 演算子の概要を、演算子のカテゴリの優先順位が高い順に一覧表示します。 同じカテゴリ内の演算子の優先順位は同じです。

カテゴリ 説明
プライマリ i
@i
識別子式
(x) かっこで囲まれた式
x[i] Lookup
x{y} 項目アクセス
x(...) 関数の呼び出し
{x, y, ...} リストの初期化
[ i = x, ... ] レコードの初期化
... 未実装
単項演算子 +x ID
-x 否定
notx 論理否定
メタデータ xmetay メタデータの関連付け
乗算 x * y 乗算
x / y 除算
加法 x + y 加算
x - y 減算
リレーショナル x< y より小さい
x > y より大きい
x<= y 以下
x >= y 以上
等式 x = y 等しい
x<> y 等しくない
型アサーション xasy 互換性のある null 値が許容されるプリミティブ型またはエラー
型の準拠 xisy 互換性のある null 値が許容されるプリミティブ型かどうかのテスト
論理積 xandy 論理積を簡単に求めます
論理和 xory 論理和を簡単に求めます
Coalesce x??y null 合体演算子

演算子とメタデータ

すべての値には、その値に関する追加情報を持つことができる関連付けられたレコード値があります。 このレコードは、値の "メタデータ レコード" と呼ばれます。 メタデータ レコードは、任意の種類の値 (null を含む) と関連付けることができます。 このような関連付けの結果が、指定されたメタデータを持つ新しい値になります。

メタデータ レコードは単なる通常のレコードであり、通常のレコードが持つことができる任意のフィールドと値を含むことができ、それ自体にメタデータ レコードがあります。 メタデータ レコードと値の関連付けは、"非侵入型" です。 メタデータ レコードを明示的に検査するものを除き、評価での値の動作は変わりません。

すべての値には、指定されていない場合でも、既定のメタデータ レコードがあります。 既定のメタデータ レコードは空です。 次の例では、Value.Metadata 標準ライブラリ関数を使用して、テキスト値のメタデータ レコードにアクセスする方法を示します。

Value.Metadata( "Mozart" )   // []

新しい値を構築する演算子または関数で値が使用されている場合、メタデータ レコードは通常、"保持されません"。 たとえば、2 つのテキスト値が & 演算子を使用して連結されている場合、結果として得られるテキスト値のメタデータは空のレコード [] となります。 次の式は同等です。

"Amadeus " & ("Mozart" meta [ Rating = 5 ])  
"Amadeus " & "Mozart"

標準ライブラリ関数 Value.RemoveMetadata および Value.ReplaceMetadata を使用すると、(メタデータを既存のメタデータにマージするのではなく) 値からすべてのメタデータを削除し、値のメタデータを置き換えることができます。

メタデータを含む結果を返す演算子は、meta 演算子だけです。

構造的に再帰的な演算子

"循環型" の値にすることができます。 例:

let l = {0, @l} in l
// {0, {0, {0, ... }}}
[A={B}, B={A}]
// [A = {{ ... }}, B = {{ ... }}]

M では、レコード、リスト、テーブルの構築を遅延させることによって循環値が処理されます。 挿入された遅延構造化値を利用できない循環値を構築しようとすると、次のエラーが発生します。

[A=B, B=A] 
// [A = Error.Record("Expression.Error", 
//         "A cyclic reference was encountered during evaluation"), 
//  B = Error.Record("Expression.Error", 
//         "A cyclic reference was encountered during evaluation"), 
// ]

M では、一部の演算子は構造再帰によって定義されます。 たとえば、レコードとリストが等しいかどうかは、対応するレコード フィールドと項目リストの等位結合によってそれぞれ定義されます。

非循環値の場合、構造再帰を適用すると、値の "有限拡大" が生成されます。共有の入れ子になった値は繰り返し走査されますが、再帰のプロセスは常に終了します。

循環値には、構造再帰を適用するときに "無限拡大" があります。 M のセマンティクスでは、このような無限拡大に対して特別な対応はしていません。たとえば、等式の循環値を比較しようとすると、通常はリソースが不足して異常終了します。

選択演算子と射影演算子

選択演算子と射影演算子を使用すると、リストとレコードの値からデータを抽出できます。

項目アクセス

値は、item-access-expression を使用して、リストまたはテーブルから、そのリストまたはテーブル内の 0 から始まる位置に基づいて、選択できます。

item-access-expression:
      item-selection
      optional-item-selection
item-selection:
      primary-expression
{item-selector}
optional-item-selection:
      primary-expression
{item-selector} ?
item-selector:
      expression

item-access-expressionx{y} は、次を返します。

  • リスト x と数値 y の場合、リスト x の項目は y の位置にあります。 リストの最初の項目には、序数インデックス 0 があると見なされます。 要求された位置がリストに存在しない場合は、エラーが発生します。

  • テーブル x と数値 y の場合、テーブル x の行は y の位置にあります。 テーブルの最初の行には、序数インデックス 0 があると見なされます。 要求された位置がテーブルに存在しない場合は、エラーが発生します。

  • テーブル x とレコード y の場合、テーブル x の行は、対応するテーブル列名と一致するフィールド名を持つフィールドのレコード y のフィールド値と一致します。 テーブルに一意の一致する行がない場合は、エラーが発生します。

例:

{"a","b","c"}{0}                        // "a" 
{1, [A=2], 3}{1}                        // [A=2] 
{true, false}{2}                        // error 
#table({"A","B"},{{0,1},{2,1}}){0}      // [A=0,B=1] 
#table({"A","B"},{{0,1},{2,1}}){[A=2]}  // [A=2,B=1]  
#table({"A","B"},{{0,1},{2,1}}){[B=3]}  // error 
#table({"A","B"},{{0,1},{2,1}}){[B=1]}  // error

item-access-expression でも形式 x{y}? がサポートされます。これは、位置 (または一致) y がリストまたはテーブル x に存在しない場合に null を返します。 y に複数の一致がある場合でも、エラーが発生します。

例:

{"a","b","c"}{0}?                       // "a" 
{1, [A=2], 3}{1}?                       // [A=2] 
{true, false}{2}?                       // null 
#table({"A","B"},{{0,1},{2,1}}){0}?     // [A=0,B=1] 
#table({"A","B"},{{0,1},{2,1}}){[A=2]}? // [A=2,B=1]  
#table({"A","B"},{{0,1},{2,1}}){[B=3]}? // null 
#table({"A","B"},{{0,1},{2,1}}){[B=1]}? // error

Item access では、アクセスされているものを除き、リストまたはテーブルの項目の評価は強制されません。 例:

{ error "a", 1, error "c"}{1}  // 1 
{ error "a", error "b"}{1}     // error "b"

item access 演算子 x{y} が評価されるときは、次が当てはまります。

  • x または y の評価中に発生したエラーが伝達されます。

  • x によって、リストまたはテーブル値が生成されます。

  • y によって数値が生成されます。または x によってテーブル値が生成される場合は、レコード値が生成されます。

  • y によって数値が生成され、y の値が負の場合は、理由コード "Expression.Error" のエラーが発生します。

  • y によって数値が生成され、y の値が x の数以上である場合は、理由コード "Expression.Error" のエラーが発生します。ただし、省略可能な演算子形式 x{y}? が使用されている場合は、値 null が返されます。

  • x によってテーブル値が生成され、y によってレコード値が生成され、xy に一致するものがない場合は、理由コード "Expression.Error" のエラーが発生します。ただし、省略可能な演算子形式 x{y}? が使用されている場合は、値 null が返されます。

  • x によってテーブル値が生成され、y によってレコード値が生成され、x 内の y に複数の一致がある場合、理由コード "Expression.Error" のエラーが発生します。

位置 y にあるもの以外の x 内の項目は、項目の選択の処理中に評価されません (ストリーミング リストまたはテーブルの場合、位置 y より前にある項目または行はスキップされます。これにより、リストまたはテーブルのソースに応じて評価が発生する可能性があります)。

Field Access

field-access-expression は、レコードから値を "選択" するため、またはレコードまたはテーブルを、より少ないフィールドのレコードまたはより少ない列のテーブルにそれぞれ "射影" するために使用されます。

field-access-expression:
      field-selection
      implicit-target-field-selection
      投影 (projection)
      implicit-target-projection
field-selection:
      primary-expression field-selector
field-selector:
      required-field-selector
      optional-field-selector
required-field-selector:

      [field-name]
optional-field-selector:
      [field-name] ?
field-name:
      generalized-identifier
      quoted-identifier
implicit-target-field-selection:
      field-selector
projection:
      primary-expression required-projection
      primary-expression optional-projection
required-projection:

      [required-selector-list]
optional-projection:
      [required-selector-list] ?
required-selector-list:
      required-field-selector
      required-selector-list
,required-field-selector
implicit-target-projection:
      required-projection
      optional-projection

field access の最も単純な形式は、required field selection です。 これは、演算子 x[y] を使用して、フィールド名でレコード内のフィールドを検索します。 フィールド yx に存在しない場合は、エラーが発生します。 形式 x[y]? は "省略可能な" フィールド選択を実行するために使用され、要求されたフィールドがレコード内に存在しない場合は null を返します。

例:

[A=1,B=2][B]       // 2 
[A=1,B=2][C]       // error 
[A=1,B=2][C]?      // null

複数のフィールドの集合アクセスは、required record projection および optional record projection の演算子によってサポートされます。 演算子 x[[y1],[y2],...] は、(y1y2... で選択された) フィールドが少ない新しいレコードにレコードを射影します。 選択したフィールドが存在しない場合は、エラーが発生します。 演算子 x[[y1],[y2],...] は、y1y2... によって選択されたフィールドを使用して、レコードを新しいレコードに射影します。フィールドが存在しない場合は、代わりに null が使用されます。 例:

[A=1,B=2][[B]]           // [B=2] 
[A=1,B=2][[C]]           // error 
[A=1,B=2][[B],[C]]?      // [B=2,C=null]

形式 [y][y]? は、識別子 _ (アンダースコア) への "短縮形" 参照としてサポートされています。 次の 2 つの式は同等です。

[A]                 
_[A]

次の例は、field access の短縮形を示しています。

let _ = [A=1,B=2] in [A] //1

形式 [[y1],[y2],...][[y1],[y2],...]? も短縮形としてサポートされており、次の 2 つの式も同じく同等です。

[[A],[B]]                 
_[[A],[B]]

短縮形は、each の短縮形と組み合わせると特に便利です。これは、_ という名前の 1 つのパラメーターの関数を導入する方法です (詳細については、「簡略化された宣言」を参照)。 2 つの短縮形の組み合わせにより、一般的な高階関数式が簡略化されます。

List.Select( {[a=1, b=1], [a=2, b=4]}, each [a] = [b]) 
// {[a=1, b=1]}

上記の式は、より長い暗号のように見える次の式と同等です。

List.Select( {[a=1, b=1], [a=2, b=4]}, (_) => _[a] = _[b]) 
// {[a=1, b=1]}

field access では、アクセスされているものを除き、フィールドの評価は強制されません。 例:

[A=error "a", B=1, C=error "c"][B]  // 1 
[A=error "a", B=error "b"][B]       // error "b"

field access 演算子 x[y]x[y]?x[[y]]、または x[[y]]? が評価されるときは、次が当てはまります。

  • x の評価中に発生したエラーが伝達されます。

  • フィールド y の評価時に発生したエラーは、フィールド y に永続的に関連付けられてから伝達されます。 今後、フィールド y にアクセスすると、同じエラーが発生します。

  • x は、レコードまたはテーブル値を生成するか、エラーが発生します。

  • 識別子 yx に存在しないフィールドを指定している場合は、理由コード "Expression.Error" のエラーが発生します。ただし、省略可能な演算子形式 ...? が使用されている場合は、値 null が返されます。

x のフィールドは、y によって指定されたものを除き、field access の処理中に評価されません。

メタデータ演算子

値のメタデータ レコードは、"meta 演算子" (x meta y) を使用して修正されます。

metadata-expression:
      unary-expression
      unary-expression
metaunary-expression

次の例では、meta 演算子を使用してメタデータ レコードを含むテキスト値を構築し、Value.Metadata を使用して結果の値のメタデータ レコードにアクセスします。

Value.Metadata( "Mozart" meta [ Rating = 5 ] ) 
// [Rating = 5 ]
Value.Metadata( "Mozart" meta [ Rating = 5 ] )[Rating] 
// 5

メタデータを組み合わせた演算子 x meta y を適用するときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • y 式は、レコードである必要があります。そうでない場合は、理由コード "Expression.Error" のエラーが発生します。

  • 結果として得られるメタデータ レコードは、y にマージされた x のメタデータ レコードです (レコードのマージのセマンティクスについては、「レコードのマージ」を参照してください)。

  • 結果として得られる値は、新しく計算されたメタデータ レコードがアタッチされた、メタデータのない x 式の値です。

標準ライブラリ関数 Value.RemoveMetadata および Value.ReplaceMetadata を使用すると、(メタデータを既存のメタデータにマージするのではなく) 値からすべてのメタデータを削除し、値のメタデータを置き換えることができます。 次の式は同等です。

x meta y  
Value.ReplaceMetadata(x, Value.Metadata(x) & y) 
Value.RemoveMetadata(x) meta (Value.Metadata(x) & y)

等値演算子

"等値演算子" = は、2 つの値が等しいかどうかを判断するために使用されます。 "非等値演算子" <> は、2 つの値が等しくないかどうかを判断するために使用されます。

equality-expression:
      relational-expression
      relational-expression
=equality-expression
      relational-expression
<>equality-expression

例:

1 = 1            // true 
1 = 2            // false 
1 <> 1           // false 
1 <> 2           // true 
null = true      // false 
null = null      // true

メタデータは、等値または非等値の比較の一部ではありません。 例:

(1 meta [ a = 1 ]) = (1 meta [ a = 2 ]) // true 
(1 meta [ a = 1 ]) = 1                  // true

等値演算子 x = y および x <> y を適用するときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • = 演算子は、値が等しい場合は true の結果となり、それ以外の場合は false となります。

  • <> 演算子は、値が等しい場合は false の結果となり、それ以外の場合は true となります。

  • メタデータ レコードは比較に含まれません。

  • xy の式の評価によって生成された値が同じ種類の値でない場合、値は等しくありません。

  • xy の式の評価によって生成された値が同じ種類の値である場合は、次に示すように、それらが等しいかどうかを判断するための特定の規則があります。

  • 常に次のようになります。

    (x = y) = not (x <> y)

等値演算子は、次の型に対して定義されています。

  • null 値は、それ自体と等しいだけです。
    null = null    // true 
    null = true    // false 
    null = false   // false
  • 論理値 truefalse は、それ自体と等しいだけです。 例:
    true = true      // true 
    false = false    // true 
    true = false     // false 
    true = 1         // false
  • 数値は、指定された精度を使用して比較されます。

    • どちらかの数値が #nan の場合、数値は同じではありません。

    • どちらの数値も #nan でない場合は、数値のビット単位の比較を使用して数値が比較されます。

    • #nan は、それ自体と等しくない唯一の値です。

      例:

        1 = 1,              // true 
        1.0 = 1             // true 
        2 = 1               // false 
        #nan = #nan         // false 
        #nan <> #nan        // true
  • 2 つの duration が 100 ナノ秒ティックの同じ数値を表している場合、それらは等しいです。

  • 2 つの time は、その部分 (時間、分、秒) の大きさが等しい場合は等しいです。

  • 2 つの date は、その部分 (年、月、日) の大きさが等しい場合は等しいです。

  • 2 つの datetime は、その部分 (年、月、日、時、分、秒) の大きさが等しい場合は等しいです。

  • 2 つの datetimezone は、対応する UTC datetime が等しい場合は等しいです。 対応する UTC datetime に到達するために、hour/minute オフセットが datetimezone の datetime 部分から減算されます。

  • 2 つのテキスト値が、序数、大文字と小文字の区別、カルチャを認識しない比較を使用していて、同じ長さで対応する位置に同じ文字がある場合、それらは等しいです。

  • 次のすべてに該当する場合、2 つのリストの値は等しいです。

    • 両方のリストに同じ数の項目が含まれている。

    • リスト内の対応する項目のそれぞれの位置の値が等しい。 つまり、リストに同じ項目が含まれているだけでなく、項目が同じ順序になっている必要があります。

      例:

        {1, 2} = {1, 2}     // true 
        {2, 1} = {1, 2}     // false 
        {1, 2, 3} = {1, 2}  // false
      
  • 次のすべてに該当する場合、2 つのレコードは等しいです。

    • フィールドの数が同じ。

    • 一方のレコードの各フィールド名が、もう一方のレコードにも存在している。

    • 一方のレコードの各フィールドの値が、もう一方のレコードの同じような名前のフィールドと等しい。

      例:

        [ A = 1, B = 2 ] = [ A = 1, B = 2 ]        // true 
        [ B = 2, A = 1 ] = [ A = 1, B = 2 ]        // true 
        [ A = 1, B = 2, C = 3 ] = [ A = 1, B = 2 ] // false 
        [ A = 1 ] = [ A = 1, B = 2 ]               // false
      
  • 次のすべてに該当する場合、2 つのテーブルは等しいです。

    • 列の数が同じ。

    • 一方のテーブル内の各列名が、もう一方のテーブルにも存在している。

    • 行の数が同じ。

    • 各行に、対応するセルと同じ値がある。

      例:

        #table({"A","B"},{{1,2}}) = #table({"A","B"},{{1,2}}) // true 
        #table({"A","B"},{{1,2}}) = #table({"X","Y"},{{1,2}}) // false 
        #table({"A","B"},{{1,2}}) = #table({"B","A"},{{2,1}}) // true
      
  • 関数の値は、それ自体と等しいですが、別の関数の値と等しいかどうかはわかりません。 2 つの関数値が等しいと見なされた場合、呼び出されると同じように動作します。

    指定された 2 つの関数値は、常に同じ等値関係を持ちます。

  • 型の値は、それ自体と等しいですが、別の型の値と等しいかどうかはわかりません。 2 つの型の値が等しいと見なされた場合、一致するかどうかを照会したときの動作は同じになります。

    指定された 2 つの型の値は、常に同じ等値関係を持ちます。

関係演算子

<><=、および >= の各演算子は "関係演算子" と呼ばれます。

relational-expression:
      additive-expression
      additive-expression
<relational-expression
      additive-expression
>relational-expression
      additive-expression
<= _relational-expression
      additive-expression >=relational-expression

これらの演算子は、次の表に示すように、2 つの値の間の相対順序の関係を決定するために使用されます。

操作 結果
x < y xy より小さい場合は true、それ以外の場合は false
x > y xy より大きい場合は true、それ以外の場合は false
x <= y xy 以下の場合は true、それ以外の場合は false
x >= y xy 以上の場合は true、それ以外の場合は false

例:

0 <= 1            // true 
null < 1          // null 
null <= null      // null 
"ab" < "abc"      // true 
#nan >= #nan      // false  
#nan <= #nan      // false

関係演算子を含む式を評価するときは、次が当てはまります。

  • x または y のオペランド式の評価中に発生したエラーが伝達されます。

  • x 式と y 式の両方を評価することによって生成される値は、binary、date、datetime、datetimezone、duration、logical、number、null、text、または time の値である必要があります。 それ以外の場合は、理由コード "Expression.Error" のエラーが発生します。

  • 両方のオペランドは、同じ種類の値または null である必要があります。 それ以外の場合は、理由コード "Expression.Error" のエラーが発生します。

  • いずれかまたは両方のオペランドが null の場合、結果は null 値になります。

  • 2 つの binary は、バイトごとに比較されます。

  • 2 つの date は、年の部分が比較され、等しい場合は月の部分、さらに等しい場合は日の部分というように比較されます。

  • 2 つの datetime は、年の部分が比較され、等しい場合は月の部分、さらに等しい場合は日の部分、さらに等しい場合は時の部分、さらに等しい場合は分の部分、さらに等しい場合は秒の部分というように比較されます。

  • 2 つの datetimezone は、それらの hour/minute オフセットを減算して UTC に正規化してから、その datetime コンポーネントを比較することによって比較されます。

  • 2 つの duration は、それらが表す 100 ナノ秒ティックの合計数に従って比較されます。

  • 2 つの logical は、truefalse よりも大きいと見なされるように比較されます。

  • 2 つの数値 xy は、IEEE 754 標準の規則に従って比較されます。

    • いずれかのオペランドが #nan の場合、結果はすべての関係演算子に対して false になります。

    • どちらのオペランドも #nan でない場合、演算子によって順序 -∞ < -max < ... < -min < -0.0 = +0.0 < +min < ... < +max < +∞ 対して 2 つの floatingpoint オペランドの値が比較されます。ここで、min と max は、表すことができる最小および最大の正の有限値です。 -∞ と +∞ の M 名は -#infinity および #infinity です。

      この順序の主な影響は次のとおりです。

      • 負のゼロと正のゼロは等しいと見なされる。

      • -#infinity 値は、他のすべての数値よりも小さいと見なされるが、別の -#infinity と等しい。

      • #infinity 値は、他のすべての数値よりも大きいと見なされるが、別の #infinity と等しい。

  • 2 つの text は、文字ごとの序数、大文字と小文字の区別、カルチャを認識しない比較を使用して比較されます。

  • 2 つの time は、時の部分が比較され、等しい場合は分の部分、さらに等しい場合は秒の部分というように比較されます。

条件付き論理演算子

and 演算子と or 演算子は、条件付き論理演算子と呼ばれます。

logical-or-expression:
      logical-and-expression
logical-and-expression
orlogical-or-expression
logical-and-expression:
      is-expression
      is-expression
andlogical-and-expression

or 演算子は、少なくとも 1 つのオペランドが true の場合に true を返します。 右辺オペランドは、左辺オペランドが true でない場合に限り評価されます。

and 演算子は、少なくとも 1 つのオペランドが false の場合に false を返します。 右辺オペランドは、左辺オペランドが false でない場合に限り評価されます。

次に示されている or 演算子と and 演算子の真理値表には、垂直軸で左辺オペランド式を評価した結果と、水平軸で右辺オペランド式を評価した結果があります。

and true false null error
true true false null error
false false false false false
null null false null error
error error error error error
or true false null error
or true false null error
true true true true true
false true false null error
null true null null error
error error error error error

条件付き論理演算子を含む式を評価するときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • 条件付き論理演算子は、型 logical および null に対して定義されています。 オペランド値がこれらの型ではない場合は、理由コード "Expression.Error" のエラーが発生します。

  • 結果は論理値になります。

  • x または y では、xtrue に評価されない場合にのみ、式 y が評価されます。

  • x および y では、xfalse に評価されない場合にのみ、式 y が評価されます。

最後の 2 つのプロパティは、条件付き論理演算子にその "条件付き" 修飾を指定します。プロパティは "ショートサーキット" とも呼ばれます。 これらのプロパティは、コンパクトな "保護された述語" を記述するのに役立ちます。 たとえば、次の式は同等です。

d <> 0 and n/d > 1 if d <> 0 then n/d > 1 else false

算術演算子

+-*、および / の各演算子は "算術演算子" です。

additive-expression:
      multiplicative-expression
      additive-expression
+multiplicative-expression
      additive-expression
-multiplicative-expression
multiplicative-expression:
      metadata- expression
      multiplicative-expression
*metadata-expression
      multiplicative-expression
/metadata-expression

適合率

M の数値は、さまざまなソースからの数値についてできるだけ多くの情報を保持するため、さまざまな表現を使用して格納されます。 数値は、必要に応じて、それらに適用された演算子によって、ある表現から別の表現に変換されるだけです。 M では、次の 2 つの精度がサポートされています。

適合率 セマンティクス
Precision.Decimal ±1.0 x 10-28 から ±7.9 x 1028 および 28 - 29 の有効桁数を持つ 128 ビットの 10 進数表現。
Precision.Double 仮数と指数を使用した科学的表現は、64 ビットバイナリ倍精度 IEEE 754 算術標準 IEEE 754-2008 に準拠しています。

算術演算を実行するには、精度を選択し、両方のオペランドをその精度に変換します (必要な場合)。次に、実際の操作を実行し、最後に選択した精度で数値を返します。

組み込みの算術演算子 (+-*/) では、倍精度が使用されます。 標準ライブラリ関数 (Value.AddValue.SubtractValue.MultiplyValue.Divide) を使用すると、特定の精度モデルを使用してこれらの操作を要求できます。

  • 数値のオーバーフローはできません。#infinity または -#infinity は、大きすぎて表現できない大きさの値を表します。

  • 数値のアンダーフローはできません。0 または -0 は、小さすぎて表現できない大きさの値を表します。

  • IEEE 754 の特別な値 #nan (NaN (非数)) は、算術的に無効なケース (0 で 0 を除算など) をカバーするために使用されます。

  • 10 進精度から倍精度への変換は、対応する最も近い double 値に 10 進数を丸めることで実行されます。

  • 倍精度から 10 進精度への変換は、double 値を最も近い 10 進値に丸め、必要に応じて #infinity 値または -#infinity 値にオーバーフローすることで実行されます。

加算演算子

加算演算子 (x + y) の解釈は、次のように、評価された式 x と y の値の種類によって異なります。

x y 結果 解釈
type number type number type number 数値の合計
type number null null
null type number null
type duration type duration type duration 大きさの数値の合計
type duration null null
null type duration null
typedatetime type duration typedatetime 期間による datetime のオフセット
type duration typedatetime typedatetime
typedatetime null null
null typedatetime null

この表では、typedatetimetype datetype datetimetype datetimezonetype time のいずれかを表します。 duration と何らかの datetime 型の値を加算すると、結果の値は同じ型になります。

表に記載されている以外の値の組み合わせでは、理由コード "Expression.Error" のエラーが発生します。 各組み合わせについては、以降のセクションで説明します。

いずれかのオペランドの評価時に発生したエラーが伝達されます。

数値の合計

2 つの数値の合計は、数値を生成する "加算演算子" を使用して計算されます。

例:

1 + 1             // 2 
#nan + #infinity  // #nan

数値に対する加算演算子 + では倍精度が使用されます。標準ライブラリ関数 Value.Add を使用して、10 進精度を指定できます。 数値の合計を計算するときは、次が当てはまります。

  • 倍精度の合計は、64 ビットのバイナリ倍精度 IEEE 754 の算術演算 IEEE 754-2008 の規則に従って計算されます。 次の表に、0 以外の有限値、0、無限大、および NaN のすべての可能な組み合わせの結果を示します。 この表では、xy は 0 以外の有限値であり、zx + y の結果です。 xy が同じ大きさで符号が逆の場合、z は正のゼロになります。 x + y が大きすぎて変換先の型で表せない場合、zx + y と同じ符号を持つ無限大になります。

    + y +0 -0 +∞ -∞ NaN
    x z x x +∞ -∞ NaN
    +0 y +0 +0 +∞ -∞ NaN
    -0 y +0 -0 +∞ -∞ NaN
    +∞ +∞ +∞ +∞ +∞ NaN NaN
    -∞ -∞ -∞ -∞ NaN -∞ NaN
    NaN NaN NaN NaN NaN NaN NaN
  • 10 進精度での合計は、精度を失うことなく計算されます。 結果のスケールは、2 つのオペランドのスケールのうち大きい方になります。

期間の和

2 つの duration の合計は、duration によって表される 100 ナノ秒ティックの数の合計を表す duration です。 例:

#duration(2,1,0,15.1) + #duration(0,1,30,45.3) 
// #duration(2, 2, 31, 0.4)

期間による datetime のオフセット

datetimex と duration yx + y を使用して加算して、線形タイムライン上の x からの距離がちょうど y の大きさである新しい datetime を計算することができます。 ここでは、datetimeDateDateTimeDateTimeZoneTime のいずれかを表し、null 以外の結果も同じ型になります。 duration による datetime オフセットは、次のように計算できます。

  • エポック値以降の datetime の日数が指定されている場合は、次の情報要素を使用して新しい datetime を作成します。

    • y の大きさを 24 時間の 100 ナノ秒ティックの数で除算し、結果の小数部分を切り捨てて、この値をエポックから x の日に加算することで、エポックからの新しい日数を計算します。

    • y の大きさを午前 0 時以降の x のティックに加算し、24 時間の 100 ナノ秒ティックの数を法として、午前 0 時以降の新しいティックを計算します。 x で午前 0 時以降のティックの値が指定されていない場合、値 0 が使用されます。

    • 変わらない UTC からの minute オフセットに対して x の値をコピーします。

  • エポック値以降の datetime の日数が指定されていない場合は、次の指定された情報要素を使用して新しい datetime を作成します。

    • y の大きさを午前 0 時以降の x のティックに加算し、24 時間の 100 ナノ秒ティックの数を法として、午前 0 時以降の新しいティックを計算します。 x で午前 0 時以降のティックの値が指定されていない場合、値 0 が使用されます。

    • エポック以降の日数と、変わらない UTC からの minute オフセットに対して x の値をコピーします。

次の例では、datetime で "エポック以降の日数" を指定する場合の絶対時間的加算の計算を示しています。

#date(2010,05,20) + #duration(0,8,0,0) 
    //#datetime( 2010, 5, 20, 8, 0, 0 ) 
    //2010-05-20T08:00:00 
 
#date(2010,01,31) + #duration(30,08,0,0) 
    //#datetime(2010, 3, 2, 8, 0, 0) 
    //2010-03-02T08:00:00 
 
#datetime(2010,05,20,12,00,00,-08) + #duration(0,04,30,00) 
    //#datetime(2010, 5, 20, 16, 30, 0, -8, 0) 
    //2010-05-20T16:30:00-08:00 
 
#datetime(2010,10,10,0,0,0,0) + #duration(1,0,0,0) 
   //#datetime(2010, 10, 11, 0, 0, 0, 0, 0) 
   //2010-10-11T00:00:00+00:00

次の例では、指定された時間の duration による datetime のオフセットの計算を示しています。

#time(8,0,0) + #duration(30,5,0,0) 
   //#time(13, 0, 0) 
   //13:00:00

減算演算子

減算演算子 (x - y) の解釈は、次のように、評価された式 xy の値の種類によって異なります。

x Y 結果 解釈
type number type number type number 数値の差
type number null null
null type number null
type duration type duration type duration 大きさの数値の差
type duration null null
null type duration null
typedatetime typedatetime type duration datetime から datetime までの期間
typedatetime type duration typedatetime 否定された期間による datetime のオフセット
typedatetime null null
null typedatetime null

この表では、typedatetimetype datetype datetimetype datetimezonetype time のいずれかを表します。 何らかの datetime 型の値から duration を減算すると、結果の値は同じ型になります。

表に記載されている以外の値の組み合わせでは、理由コード "Expression.Error" のエラーが発生します。 各組み合わせについては、以降のセクションで説明します。

いずれかのオペランドの評価時に発生したエラーが伝達されます。

数値の差

2 つの数値の差は、数値を生成する "減算演算子" を使用して計算されます。 例:

1 - 1                // 0 
#nan - #infinity     // #nan

数値に対する減算演算子 - では倍精度が使用されます。標準ライブラリ関数 Value.Subtract を使用して、10 進精度を指定できます。 数値の差を計算するときは、次が当てはまります。

  • 倍精度の差は、64 ビットのバイナリ倍精度 IEEE 754 の算術演算 IEEE 754-2008 の規則に従って計算されます。 次の表に、0 以外の有限値、0、無限大、および NaN のすべての可能な組み合わせの結果を示します。 この表では、xy は 0 以外の有限値であり、zx - y の結果です。 xy が等しい場合、z は正のゼロになります。 x - y が大きすぎて変換先の型で表せない場合、zx - y と同じ符号を持つ無限大になります。

    - y +0 -0 +∞ -∞ NaN
    x z x x -∞ +∞ NaN
    +0 -y +0 +0 -∞ +∞ NaN
    -0 -y -0 +0 -∞ +∞ NaN
    +∞ +∞ +∞ +∞ NaN +∞ NaN
    -∞ -∞ -∞ -∞ -∞ NaN NaN
    NaN NaN NaN NaN NaN NaN NaN
  • 10 進精度での差は、精度を失うことなく計算されます。 結果のスケールは、2 つのオペランドのスケールのうち大きい方になります。

期間の差

2 つの duration の差は、各 duration によって表される 100 ナノ秒ティックの数の差を表す duration です。 例:

#duration(1,2,30,0) - #duration(0,0,0,30.45) 
// #duration(1, 2, 29, 29.55)

否定された期間による datetime のオフセット

datetimex と duration yx - y を使用して減算して、新しい datetime を計算できます。 ここでは、datetimedatedatetimedatetimezonetime のいずれかを表します。 結果として得られる datetime には、ちょうど y の大きさの線形タイムライン上の y の符号とは逆方向にある x からの距離があります。 正の duration を減算すると、x を基準とした相対的に時間を戻した結果になるのに対し、負の値を減算すると、時間を進ませる結果になります。

#date(2010,05,20) - #duration(00,08,00,00) 
   //#datetime(2010, 5, 19, 16, 0, 0) 
   //2010-05-19T16:00:00 
#date(2010,01,31) - #duration( 30,08,00,00) 
   //#datetime(2009, 12, 31, 16, 0, 0) 
   //2009-12-31T16:00:00

2 つの datetime 間の duration

2 つの datetimestut - u を使用して減算して、それらの間の duration を計算できます。 ここでは、datetimedatedatetimedatetimezonetime のいずれかを表します。 t から u を減算することによって生成される duration は、u に加算したときに t にならなければなりません。

#date(2010,01,31) - #date(2010,01,15) 
// #duration(16,00,00,00) 
// 16.00:00:00 
 
#date(2010,01,15)- #date(2010,01,31) 
// #duration(-16,00,00,00) 
// -16.00:00:00 
 
#datetime(2010,05,20,16,06,00,-08,00) - 
#datetime(2008,12,15,04,19,19,03,00) 
// #duration(521,22,46,41)
// 521.22:46:41

u > t のときに t - u を減算すると、負の duration になります。

#time(01,30,00) - #time(08,00,00) 
// #duration(0, -6, -30, 0)

t - u を使用して 2 つの datetime を減算するときは、次が当てはまります。

  • u + (t - u) = t

乗算演算子

乗算演算子 (x * y) の解釈は、次のように、評価された式 x と y の値の種類によって異なります。

X Y 結果 解釈
type number type number type number 数値の積
type number null null
null type number null
type duration type number type duration duration の倍数
type number type duration type duration duration の倍数
type duration null null
null type duration null

表に記載されている以外の値の組み合わせでは、理由コード "Expression.Error" のエラーが発生します。 各組み合わせについては、以降のセクションで説明します。

いずれかのオペランドの評価時に発生したエラーが伝達されます。

数値の積

2 つの数値の積は、数値を生成する "乗算演算子" を使用して計算されます。 例:

2 * 4                // 8 
6 * null             // null 
#nan * #infinity     // #nan

数値に対する乗算演算子 * では倍精度が使用されます。標準ライブラリ関数 Value.Multiply を使用して、10 進精度を指定できます。 数値の積を計算するときは、次が当てはまります。

  • 倍精度の積は、64 ビットのバイナリ倍精度 IEEE 754 の算術演算 IEEE 754-2008 の規則に従って計算されます。 次の表に、0 以外の有限値、0、無限大、および NaN のすべての可能な組み合わせの結果を示します。 この表では、xy は正の有限値です。 zx * y の結果です。 結果が変換先の型に対して大きすぎる場合、z は無限大です。 結果が変換先の型に対して小さすぎる場合、z は 0 です。

    * +y -y +0 -0 +∞ -∞ NaN
    +x +z -Z +0 -0 +∞ -∞ NaN
    -x -Z +z -0 +0 -∞ +∞ NaN
    +0 +0 -0 +0 -0 NaN NaN NaN
    -0 -0 +0 -0 +0 NaN NaN NaN
    +∞ +∞ -∞ NaN NaN +∞ -∞ NaN
    -∞ -∞ +∞ NaN NaN -∞ +∞ NaN
    NaN NaN NaN NaN NaN NaN NaN NaN
  • 10 進精度の積は、精度を失うことなく計算されます。 結果のスケールは、2 つのオペランドのスケールのうち大きい方になります。

duration の倍数

duration と数値の積は、duration オペランド x 数値オペランドによって表される 100 ナノ秒ティックの数値を表す duration です。 例:

#duration(2,1,0,15.1) * 2 
// #duration(4, 2, 0, 30.2)

除算演算子

除算演算子 (x / y) の解釈は、次のように、評価された式 xy の値の種類によって異なります。

X Y 結果 解釈
type number type number type number 数値の商
type number null null
null type number null
type duration type number type duration duration の小数部
type duration type duration type duration duration の数値の商
type duration null null
null type duration null

表に記載されている以外の値の組み合わせでは、理由コード "Expression.Error" のエラーが発生します。 各組み合わせについては、以降のセクションで説明します。

いずれかのオペランドの評価時に発生したエラーが伝達されます。

数値の商

2 つの数値の商は、数値を生成する "除算演算子" を使用して計算されます。 例:

8 / 2               // 4 
8 / 0               // #infinity 
0 / 0               // #nan 
0 / null            // null 
#nan / #infinity    // #nan

数値に対する除算演算子 / では倍精度が使用されます。標準ライブラリ関数 Value.Divide を使用して、10 進精度を指定できます。 数値の商を計算するときは、次が当てはまります。

  • 倍精度の商は、64 ビットのバイナリ倍精度 IEEE 754 の算術演算 IEEE 754-2008 の規則に従って計算されます。 次の表に、0 以外の有限値、0、無限大、および NaN のすべての可能な組み合わせの結果を示します。 この表では、xy は正の有限値です。 zx / y の結果です。 結果が変換先の型に対して大きすぎる場合、z は無限大です。 結果が変換先の型に対して小さすぎる場合、z は 0 です。

    / +y -y +0 -0 +∞ -∞ NaN
    +x +z -Z +∞ -∞ +0 -0 NaN
    -x -Z +z -∞ +∞ -0 +0 NaN
    +0 +0 -0 NaN NaN +0 -0 NaN
    -0 -0 +0 NaN NaN -0 +0 NaN
    +∞ +∞ -∞ +∞ -∞ NaN NaN NaN
    -∞ -∞ +∞ -∞ +∞ NaN NaN NaN
    NaN NaN NaN NaN NaN NaN NaN NaN
  • 10 進精度での合計は、精度を失うことなく計算されます。 結果のスケールは、2 つのオペランドのスケールのうち大きい方になります。

duration の商

2 つの duration の商は、duration によって表される 100 ナノ秒ティックの数の商を表す duration です。 例:

#duration(2,0,0,0) / #duration(0,1,30,0) 
// 32

スケールされた duration

duration x と数値 y の商は、duration x と数値 y によって表される 100 ナノ秒ティックの数値の商を表す duration です。 例:

#duration(2,0,0,0) / 32 
// #duration(0,1,30,0)

構造体の組み合わせ

複合演算子 (x & y) は、次の種類の値に対して定義されています。

X Y 結果 解釈
type text type text type text 連結
type text null null
null type text null
type date type time type datetime マージ
type date null null
null type time null
type list type list type list 連結
type record type record type record マージ
type table type table type table 連結

連結

x & y を使用して、2 つのテキスト、2 つのリスト、または 2 つのテーブルの値を連結できます。

次の例は、テキスト値の連結を示しています。

"AB" & "CDE"     // "ABCDE"

次の例は、リストの連結を示しています。

{1, 2} & {3}     // {1, 2, 3}

x & y を使用して 2 つの値を連結するときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • x または y のいずれかの項目にエラーが含まれている場合、エラーは伝達されません。

  • 2 つのテキスト値を連結した結果は、x の直後に y が続く値を含むテキスト値になります。 オペランドのいずれか一方が null でもう一方がテキスト値の場合、結果は null になります。

  • 2 つのリストを連結した結果は、x のすべての項目とその後に y のすべての項目が含まれたリストになります。

  • 2 つのテーブルを連結した結果は、2 つのオペランド テーブルの列の和集合を持つテーブルになります。 x の列の順序は保持され、その後に y にのみ表示される列が続き、その相対順序が保持されます。 いずれかのオペランドでのみ表示される列の場合、もう一方のオペランドのセル値を入力するために null が使用されます。

マージ

レコードのマージ

x & y を使用して 2 つのレコードをマージすると、xy の両方のフィールドを含むレコードが生成されます。

次の例は、レコードのマージについて示しています。

[ x = 1 ] & [ y = 2 ]                // [ x = 1, y = 2 ] 
[ x = 1, y = 2 ] & [ x = 3, z = 4 ]  // [ x = 3, y = 2, z = 4 ]

x + y を使用して 2 つのレコードをマージするときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • フィールドが xy の両方に表示される場合、y の値が使用されます。

  • 結果として得られるレコード内のフィールドの順序は、x のもので、その後に x に含まれていない y のフィールドが、y に表示されるのと同じ順序で続きます。

  • レコードをマージしても、値の評価は行われません。

  • フィールドにエラーが含まれているため、エラーは発生しません。

  • 結果はレコードになります。

date と time のマージ

date x と time y を、x & y を使用してマージして、xy の両方の部分を結合する datetime を生成できます。

次の例は、date と time のマージを示しています。

#date(2013,02,26) & #time(09,17,00) 
// #datetime(2013,02,26,09,17,00)

x + y を使用して 2 つのレコードをマージするときは、次が当てはまります。

  • x または y の式の評価中に発生したエラーが伝達されます。

  • 結果は datetime になります。

単項演算子

+-not 演算子は単項演算子です。

unary-expression:
      type-expression

      +unary expression
      -unary expression
      notunary expression

単項プラス演算子

単項プラス演算子 (+x) は、次の種類の値に対して定義されています。

X 結果 解釈
type number type number 単項プラス
type duration type duration 単項プラス
null `null

その他の値の場合、理由コード "Expression.Error" のエラーが発生します。

単項プラス演算子を使用すると、+ 符号を数値、datetime、または null 値に適用できます。 結果は同じ値になります。 例:

+ - 1                 // -1 
+ + 1                 // 1 
+ #nan                // #nan 
+ #duration(0,1,30,0) // #duration(0,1,30,0)

単項プラス演算子 +x を評価するときは、次が当てはまります。

  • x の評価時に発生したエラーが伝達されます。

  • x の評価結果が数値でない場合は、理由コード "Expression.Error" のエラーが発生します。

単項マイナス演算子

単項マイナス演算子 (-x) は、次の種類の値に対して定義されています。

X 結果 解釈
type number type number 否定
type duration type duration 否定
null null

その他の値の場合、理由コード "Expression.Error" のエラーが発生します。

単項マイナス演算子は、数値または duration の符号を変更するために使用されます。 例:

- (1 + 1)       // -2 
- - 1           // 1 
- - - 1         // -1 
- #nan          // #nan 
- #infinity     // -#infinity 
- #duration(1,0,0,0)  // #duration(-1,0,0,0) 
- #duration(0,1,30,0) // #duration(0,-1,-30,0)

単項マイナス演算子 -x を評価するときは、次が当てはまります。

  • x の評価時に発生したエラーが伝達されます。

  • 式が数値の場合、結果は、符号が変更された式 x からの数値になります。 値が NaN の場合、結果も NaN になります。

論理否定演算子

論理否定演算子 (not) は、次の種類の値に対して定義されています。

X 結果 解釈
type logical type logical 否定
null null

この演算子は、指定された論理値に対して論理的な not 演算を計算します。 例:

not true             // false 
not false            // true 
not (true and true)  // false

論理否定演算子 not x を評価するときには、次が当てはまります。

  • x の評価時に発生したエラーが伝達されます。

  • 式 x の評価から生成された値は論理値である必要があります。または、理由コード "Expression.Error" のエラーが発生する必要があります。 値が true の場合、結果は false になります。 オペランドが false の場合、結果は true になります。

結果は論理値になります。

型演算子

演算子 isas は、型演算子として知られています。

型の互換性演算子

型の互換性演算子 x is y は、次の種類の値に対して定義されています。

X Y 結果
type any nullable-primitive-type type logical

x is y は、x の指定の型が y と互換性がある場合には true を返し、x の帰属の型が y と互換性がない場合は false を返します。 ynullable-primitive-type である必要があります。

is-expression:
      as-expression
      is-expression
isnullable-primitive-type
nullable-primitive-type:

      nullableopt primitive-type

is 演算子でサポートされている型の互換性は、一般的な型の互換性のサブセットであり、次の規則を使用して定義されています。

  • x が null の場合、yany 型、null 型、または null 許容型であれば互換性があります。

  • x が null 以外で、互換性があり、x のプリミティブ型である場合は、y と同じです。

x is y を評価するときには、次が当てはまります。

  • x の評価時に発生したエラーが伝達されます。

型アサーション演算子

型アサーション演算子 x as y は、次の種類の値に対して定義されています。

X Y 結果
type any nullable-primitive-type type any

x as y は、is 演算子により、値 xy と互換性があることをアサートします。 互換性がない場合は、エラーが発生します。 ynullable-primitive-type である必要があります。

as-expression:
      equality-expression
      as-expression
asnullable-primitive-type

x as y は次のように評価されます。

  • 型互換性チェック x is y が実行され、そのテストが成功した場合、アサーションは変更されていない x を返します。

  • 互換性チェックが失敗した場合は、理由コード "Expression.Error" のエラーが発生します。

例:

1 as number               // 1 
"A" as number             // error 
null as nullable number   // null

x as y を評価するときには、次が当てはまります。

  • x の評価時に発生したエラーが伝達されます。

合体演算子

合体演算子 ?? では、左側のオペランドが null でない場合はその結果が返され、それ以外の場合は右側のオペランドの結果が返されます。 右側のオペランドは、左側のオペランドが null である場合にのみ評価されます。