関数
"関数" は、一連の引数値から単一の値へのマッピングを表す値です。 関数は、一連の入力値 (引数値) を指定することによって呼び出され、1 つの出力値 (戻り値) を生成します。
関数の記述
関数は function-expression を使用して記述されます。
function-expression:
(
parameter-listopt)
function-return-typeopt=>
function-body
function-body:
expression
parameter-list:
fixed-parameter-list
fixed-parameter-list,
optional-parameter-list
optional-parameter-list
fixed-parameter-list:
パラメーター
parameter,
fixed-parameter-list
パラメーターを使用します。
parameter-name parameter-typeopt
parameter-name:
identifier
parameter-type:
assertion
function-return-type:
assertion
assertion:
as
nullable-primiitve-type
optional-parameter-list:
optional-parameter
optional-parameter,
optional-parameter-list
optional-parameter:
optional
parameter
nullable-primitve-type
nullable
optprimitive-type
次に示すのは、厳密に 2 つの値 (x
と y
) を必要とし、それらの値に +
演算子を適用した結果を生成する関数の例です。 x
と y
は、関数の parameter-list に含まれている "パラメーター" で、x + y
は function-body です。
(x, y) => x + y
function-expression を評価した結果として、関数値が生成されます (function-body は評価されません)。 このドキュメントの慣例として、関数値は (関数式とは異なり)、parameter-list と共に表示されますが、function-body の代わりに省略記号 (...
) が付きます。 たとえば、上の関数式が評価されると、次の関数値として表示されます。
(x, y) => ...
関数値には、次の演算子が定義されています。
演算子 | 結果 |
---|---|
x = y |
等しい |
x <> y |
等しくない |
関数値のネイティブ型は、パラメーター名を一覧表示し、すべてのパラメーターの型と戻り値の型が any
になるように指定する、(組み込み型 function
から派生した) カスタム関数型です (関数の型の詳細については、「関数の型」を参照してください。)
関数の呼び出し
関数の function-body は、invoke-expression を使用して関数値を "呼び出す" ことによって実行されます。 関数値を呼び出すと、関数値の function-body が評価され、値が返されるか、エラーが発生します。
invoke-expression:
primary-expression(
argument-listopt)
argument-list:
expression-list
関数値が呼び出されるたびに、値のセットが argument-list として指定され、関数に対して "引数" が呼び出されます。
argument-list は、式のリストとして固定数の引数を直接指定するために使用されます。 次の例では、フィールドに関数値を含むレコードを定義してから、そのレコードの別のフィールドから関数を呼び出します。
[
MyFunction = (x, y, z) => x + y + z,
Result1 = MyFunction(1, 2, 3) // 6
]
関数を呼び出すときには、次が当てはまります。
関数の function-body を評価するために使用される環境には、各パラメーターに対応する、パラメーターと同じ名前の変数が含まれています。 各パラメーターの値は、「パラメーター」で定義されているように、invoke-expression の argument-list から構築された値に対応しています。
関数の引数に対応するすべての式は、function-body が評価される前に評価されます。
expression-list の式を評価すると、エラーが発生するか、function-body が伝達されます。
argument-list から構築された引数の数が、関数のパラメーターと互換性がある必要があります。そうでない場合は、理由コード
"Expression.Error"
のエラーが発生します。 一致を確認するためのプロセスは、「パラメーター」で定義されています。
パラメーター
parameter-list に存在することができるパラメーターには、次の 2 種類があります。
"必須" パラメーターは、関数が呼び出されたときに、パラメーターに対応する引数を常に指定する必要があることを示します。 必須パラメーターは、parameter-list で最初に指定する必要があります。 次の例の関数では、必須パラメーター
x
とy
を定義しています。[ MyFunction = (x, y) => x + y, Result1 = MyFunction(1, 1), // 2 Result2 = MyFunction(2, 2) // 4 ]
"省略可能な" パラメーターは、関数が呼び出されたときに、パラメーターに対応する引数を指定できるが、指定する必要はないことを示します。 関数が呼び出されたときに、省略可能なパラメーターに対応する引数が指定されていない場合は、代わりに
null
値が使用されます。 省略可能なパラメーターは、parameter-list の必須パラメーターの後に指定する必要があります。 次の例の関数では、固定パラメーターx
と省略可能なパラメーターy
を定義しています。[ MyFunction = (x, optional y) => if (y = null) x else x + y, Result1 = MyFunction(1), // 1 Result2 = MyFunction(1, null), // 1 Result3 = MyFunction(2, 2), // 4 ]
関数が呼び出されたときに指定される引数の数が、パラメーター リストと一致している必要があります。 関数 F
に対する一連の引数 A
の一致は、次のように計算されます。
値 N は、argument-list から構築された引数
A
の数を表すものとします。 例:MyFunction() // N = 0 MyFunction(1) // N = 1 MyFunction(null) // N = 1 MyFunction(null, 2) // N = 2 MyFunction(1, 2, 3) // N = 3 MyFunction(1, 2, null) // N = 3 MyFunction(1, 2, {3, 4}) // N = 3
値 Required は、
F
の固定パラメーターの数を表し、Optional はF
の省略可能なパラメーターの数を表すものとします。 例:() // Required = 0, Optional = 0 (x) // Required = 1, Optional = 0 (optional x) // Required = 0, Optional = 1 (x, optional y) // Required = 1, Optional = 1
次の条件に該当する場合は、引数
A
は関数F
と一致しています。- (N >= Fixed) かつ (N <= (Fixed + Optional))
- 引数の型が
F
の対応するパラメーターの型と一致している
関数に宣言された戻り値の型がある場合、次の条件に該当する場合は、関数
F
の本体の結果値は、F
の戻り値の型と一致します。- 関数のパラメーターに対して指定された引数で関数本体を評価することによって生成される値には、戻り値の型と一致する型があります。
関数本体で関数の戻り値の型と一致しない値が生成される場合、理由コード
"Expression.Error"
のエラーが発生します。
再帰関数
再帰的な関数値を記述するには、スコープ演算子 (@
) を使用して、そのスコープ内で関数を参照する必要があります。 たとえば、次のレコードには、Factorial
関数を定義するフィールドと、それを呼び出す別のフィールドが含まれています。
[
Factorial = (x) =>
if x = 0 then 1 else x * @Factorial(x - 1),
Result = Factorial(3) // 6
]
同様に、相互再帰関数は、アクセスする必要がある各関数に名前がある限り、記述できます。 次の例では、Factorial
関数の一部が 2 番目の Factorial2
関数にリファクタリングされています。
[
Factorial = (x) => if x = 0 then 1 else Factorial2(x),
Factorial2 = (x) => x * Factorial(x - 1),
Result = Factorial(3) // 6
]
クロージャ
関数は、別の関数を値として返すことができます。 この関数は、元の関数に対して 1 つ以上のパラメーターに順番に依存できます。 次の例では、フィールド MyFunction
に関連付けられている関数は、指定されたパラメーターを返す関数を返します。
[
MyFunction = (x) => () => x,
MyFunction1 = MyFunction(1),
MyFunction2 = MyFunction(2),
Result = MyFunction1() + MyFunction2() // 3
]
関数が呼び出されるたびに、パラメーターの値を保持する新しい関数値が返されます。これにより、呼び出されたときに、パラメーター値が返されるようになります。
関数と環境
パラメーターに加えて、function-expression の function-body は、関数の初期化時に環境内に存在する変数を参照できます。 たとえば、フィールド MyFunction
によって定義される関数は、囲みレコード A
のフィールド C
にアクセスします。
[
A =
[
MyFunction = () => C,
C = 1
],
B = A[MyFunction]() // 1
]
MyFunction
が呼び出されると、変数 C
を含まない環境 (B
) から呼び出される場合でも、変数 C
の値にアクセスします。
簡略化された宣言
each-expression は、_
(アンダースコア) という名前の 1 つのパラメーターを受け取る型指定されていない関数を宣言するための構文の省略形です。
each-expression:
each
each-expression-body
each-expression-body:
function-body
簡略化された宣言は、高階関数呼び出しの読みやすさを向上させるためによく使用されます。
たとえば、次の宣言のペアは意味的には同等です。
each _ + 1
(_) => _ + 1
each [A]
(_) => _[A]
Table.SelectRows( aTable, each [Weight] > 12 )
Table.SelectRows( aTable, (_) => _[Weight] > 12 )