閱讀英文

共用方式為


函式

「函式」是一種值,其代表從一組引數值到單一值的對應。 函式可以藉由提供的一組輸入值 (引數值) 叫用,並產生單一輸出值 (傳回值)。

撰寫函式

函式是使用 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
      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 參數
nullable-primitve-type
      nullable
opt primitive-type

下列是函式的範例,該函式需要兩個值 xy,並會產生將 + 運算子套用到這些值的結果。 xy 是屬於函式 parameter-list 的「參數」,而 x + y 則是 function-body

(x, y) => x + y

評估 function-expression 的結果是產生函式值 (而非評估 function-body)。 作為此文件中的慣例,函式值 (與函式運算式相對) 會與 parameter-list 一同顯示,但 function-body 則會顯示為省略符號 (...)。 例如,一旦評估了以上的函式運算式,便會顯示為下列函式值:

 (x, y) => ...

其中已為函式值定義下列運算子:

運算子 結果
x = y 等於
x <> y 不等於

函式值的原生類型是自訂函式類型 (衍生自內建類型 function),該類型會列出參數名稱和指定所有參數類型及傳回類型為 any。 (請移至函式類型以取得函式類型的詳細資料。)

叫用函式

函式的 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-expressionargument-list 建構的值,如參數中所定義。

  • 對應至函式引數的所有運算式都會在評估 function-body 前先行評估。

  • 評估 expression-listfunction-body 中運算式時引發的錯誤會進行散佈。

  • argument-list 所建構引數數量必須與函式的參數相容,否則會引發原因代碼為 "Expression.Error" 的錯誤。 判斷相容性的流程會定義在參數中。

參數

有兩種參數可能會呈現在 parameter-list 中:

  • 「必要」參數指出對應至參數的引數一律必須在叫用函式時指定。 首先,必須在 parameter-list 中指定必要參數。 下列範例中的函式會定義必要參數 xy

      [ 
          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
    
  • 若下列為 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-expressionfunction-body 可以在初始化函式時參考環境中存在的變數。 例如,欄位 MyFunction 所定義函式會存取封入記錄 A 的欄位 C

[ 
A =  
    [ 
        MyFunction = () => C, 
        C = 1 
    ], 
B = A[MyFunction]()           // 1 
]

叫用 MyFunction 時,其會存取變數 C 的值,即使是從並未包含變數 C 的環境 (B) 中叫用該函式也一樣。

簡化的宣告

each-expression 是一種語法速記,用來宣告接受名為 _ (底線) 單一參數的無類型函式。

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 )