「函式」是一種值,其代表從一組引數值到單一值的對應。 函式可以藉由提供的一組輸入值 (引數值) 叫用,並產生單一輸出值 (傳回值)。
撰寫函式
函式是使用 function-expression 撰寫的:
function-expression:
(
參數列表OPT)回傳型OPT=>功能體
function-body:
運算式
parameter-list:
fixed-parameter-list
固定參數列表,可選參數列表
optional-parameter-list
fixed-parameter-list:
參數
參數,固定參數列表
參數:
參數-名稱-參數-類型OPT
parameter-name:
識別碼
parameter-type:
原始或可空原始型態斷言
回傳類型:
原始或可空原始型態斷言
原始或可空原始型態斷言:
as
原始或可空原始型
optional-parameter-list:
optional-parameter
可選參數,可選參數列表
可選參數:
optional
參數
原始型或可歸原原始型:
nullable
OPT 原始型
下列是函式的範例,該函式需要兩個值 x 和 y,並會產生將 + 運算子套用到這些值的結果。
x 和 y 是屬於函式 parameter-list 的「參數」,而 x + y 則是 function-body:
(x, y) => x + y
評估 function-expression 的結果是產生函式值 (而非評估 function-body)。 作為此文件中的慣例,函式值 (與函式運算式相對) 會與 parameter-list 一同顯示,但 ... 則會顯示為省略符號 ()。 例如,一旦評估了以上的函式運算式,便會顯示為下列函式值:
(x, y) => ...
其中已為函式值定義下列運算子:
| 運算子 | 結果 |
|---|---|
x = y |
等於 |
x <> y |
不等於 |
函式值的原生類型是自訂函式類型 (衍生自內建類型 function),該類型會列出參數名稱和指定所有參數類型及傳回類型為 any。 (請移至函式類型以取得函式類型的詳細資料。)
叫用函式
函式的 function-body 會透過使用 invoke-expression「叫用」函式值來執行。 叫用函式值表示函式值的 function-body 會經過評估,並傳回值或引發錯誤。
invoke-expression:
主表達式(參數列表OPT)
論點列表:
表達式列表
每次叫用函式值時,都會將一組值指定為 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 中:
「必要」參數指出對應至參數的引數一律必須在叫用函式時指定。 首先,必須在 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 ]
叫用函式時指定的引數數量必須與參數清單相容。 函式 A 一組引數 F 的相容性會透過如下方式計算:
令 N 值代表從
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若下列為 true,則引數
A與函式F相容:- (N >= Fixed) 且 (N <= (Fixed + Optional))
- 引數類型與
F的對應參數類型相容
若函式具備宣告的傳回類型,則若下列為 true,函式
F主體結果值便與F的傳回類型相容:- 使用為函式參數提供的引數來評估函式主體所產生值,其具備與傳回類型相容的類型。
若函式主體所產生值與函式的傳回類型不相容,則會引發原因代碼為
"Expression.Error"的錯誤。
遞迴函式
若要撰寫遞迴函式值,則必須使用範圍運算子 (@) 來在函式的範圍內參考函式。 例如,下列記錄包含一個欄位,其定義 Factorial 函式,以及另一個呼叫該函式的欄位:
[
Factorial = (x) =>
if x = 0 then 1 else x * @Factorial(x - 1),
Result = Factorial(3) // 6
]
同樣地,您也可以撰寫相互遞迴的函式,只要需要存取的每個函式都具備名稱即可。 在下列範例中,Factorial 函式的一部分已重構至第二個 Factorial2 函式。
[
Factorial = (x) => if x = 0 then 1 else Factorial2(x),
Factorial2 = (x) => x * Factorial(x - 1),
Result = Factorial(3) // 6
]
結束
函式可以傳回另一個函式作為值。 此函式接著可以相依於原始函式的一或多個參數。 在下列範例中,與欄位 MyFunction 建立關聯的函式會傳回函式,該函式則會傳回指定給其的參數:
[
MyFunction = (x) => () => x,
MyFunction1 = MyFunction(1),
MyFunction2 = MyFunction(2),
Result = MyFunction1() + MyFunction2() // 3
]
每次叫用函式時,都會傳回保留參數值的新函式值,因此每當叫用時,都會傳回參數值。
函式和環境
除了參數外,function-expression 的 function-body 可以在初始化函式時參考環境中存在的變數。 例如,欄位 MyFunction 所定義函式會存取封入記錄 C 的欄位 A:
[
A =
[
MyFunction = () => C,
C = 1
],
B = A[MyFunction]() // 1
]
叫用 MyFunction 時,其會存取變數 C 的值,即使是從並未包含變數 B 的環境 (C) 中叫用該函式也一樣。
簡化的宣告
each-expression 是一種語法速記,用來宣告接受名為 _ (底線) 單一參數的無類型函式。
each-expression:
each
每個表達式
each-expression-body:
功能體
經簡化宣告經常用來改善高階函式引動的可讀性。
例如,下列宣告對在語意上是相等的:
each _ + 1
(_) => _ + 1
each [A]
(_) => _[A]
Table.SelectRows( aTable, each [Weight] > 12 )
Table.SelectRows( aTable, (_) => _[Weight] > 12 )