Fonctions

Une fonction est une valeur qui représente un mappage d’un ensemble de valeurs d’arguments à une valeur unique. Une fonction est appelée en fournissant un ensemble de valeurs d’entrée (valeurs d’arguments) et produit une seule valeur de sortie (valeur de retour).

Écriture de fonctions

Les fonctions sont écrites à l’aide d’un 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 :
      paramètre
      parameter
,fixed-parameter-list
parameter :
      parameter-name parameter-typeopt
parameter-name :
      identificateur
parameter-type :
      assertion
function-return-type :
      assertion
assertion :

      asnullable-primiitve-type
optional-parameter-list :
      optional-parameter
      optional-parameter
,optional-parameter-list
optional-parameter :

      optionalparameter
nullable-primitve-type
      nullable
optprimitive-type

Voici un exemple de fonction qui requiert exactement deux valeurs x et y, et qui produit le résultat de l’application de l’opérateur + à ces valeurs. x et y sont des paramètres qui font partie de la parameter-list de la fonction, et x + y est le function-body :

(x, y) => x + y

Le résultat de l’évaluation d’une function-expression est la production d’une valeur de fonction (et non l’évaluation du function-body). En guise de convention dans ce document, les valeurs de fonction (par opposition aux expressions de fonction) sont affichées avec la parameter-list mais avec des points de suspension (...) au lieu du function-body. Par exemple, une fois que l’expression de fonction ci-dessus a été évaluée, elle est affichée comme valeur de fonction suivante :

 (x, y) => ...

Les opérateurs suivants sont définis pour les valeurs de fonction :

Opérateur Résultat
x = y Égal à
x <> y Différent de

Le type natif des valeurs de fonction est un type de fonction personnalisé (dérivé du type intrinsèque function) qui liste les noms de paramètres et spécifie tous les types de paramètres et le type de retour comme étant any. (Pour plus d’informations sur les types de fonctions, consultez Types de fonctions.)

Appel de fonctions

Le function-body d’une fonction est exécuté en appelant la valeur de fonction à l’aide d’une invoke-expression. Appeler une valeur de fonction signifie que le function-body de la valeur de fonction est évalué, et qu’une valeur est retournée ou une erreur est générée.

invoke-expression :
      primary-expression
(argument-listopt)
argument-list :
      expression-list

Chaque fois qu’une valeur de fonction est appelée, un ensemble de valeurs est spécifié sous la forme d’une argument-list, appelé arguments de la fonction.

Une argument-list est utilisée pour spécifier un nombre fixe d’arguments directement sous la forme d’une liste d’expressions. L’exemple suivant définit un enregistrement avec une valeur de fonction dans un champ, puis appelle la fonction à partir d’un autre champ de l’enregistrement :

[ 
    MyFunction = (x, y, z) => x + y + z, 
    Result1 = MyFunction(1, 2, 3)           // 6
]

Ce qui suit s’applique lors de l’appel d’une fonction :

  • L’environnement utilisé pour évaluer le function-body de la fonction comprend une variable qui correspond à chaque paramètre, avec le même nom que le paramètre. La valeur de chaque paramètre correspond à une valeur construite à partir de l’argument-list de l’invoke-expression, comme défini dans Paramètres.

  • Toutes les expressions correspondant aux arguments de la fonction sont évaluées avant le function-body.

  • Les erreurs générées lors de l’évaluation des expressions dans l’expression-list ou le function-body sont propagées.

  • Le nombre d’arguments construits à partir de l’argument-list doit être compatible avec les paramètres de la fonction, sinon une erreur est générée avec le code de raison "Expression.Error". Le processus de détermination de la compatibilité est défini dans Paramètres.

Paramètres

Il existe deux genres de paramètres qui peuvent être présents dans une parameter-list :

  • Un paramètre obligatoire indique qu’un argument correspondant au paramètre doit toujours être spécifié quand une fonction est appelée. Les paramètres obligatoires doivent être spécifiés en premier dans la parameter-list. La fonction dans l’exemple suivant définit les paramètres obligatoires x et y :

      [ 
          MyFunction = (x, y) => x + y, 
    
          Result1 = MyFunction(1, 1),     // 2 
          Result2 = MyFunction(2, 2)      // 4
      ] 
    
  • Un paramètre facultatif indique qu’un argument correspondant au paramètre peut être spécifié quand une fonction est appelée, mais que cela n’est pas obligatoire. Si un argument qui correspond à un paramètre facultatif n’est pas spécifié quand la fonction est appelée, la valeur null est utilisée à la place. Les paramètres facultatifs doivent apparaître après tous les paramètres obligatoires dans une parameter-list. La fonction dans l’exemple suivant définit un paramètre fixe x et un paramètre facultatif 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
      ] 
    

Le nombre d’arguments spécifiés quand une fonction est appelée doit être compatible avec la liste de paramètres. La compatibilité d’un ensemble d’arguments A pour une fonction F est calculée comme suit :

  • Soit la valeur N représentant le nombre d’arguments A construits à partir de l’argument-list. Par exemple :

      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
    
  • Soit la valeur Required représentant le nombre de paramètres fixes de F et la valeur Optional le nombre de paramètres facultatifs de F. Par exemple :

    ()               // Required = 0, Optional = 0 
    (x)              // Required = 1, Optional = 0 
    (optional x)     // Required = 0, Optional = 1 
    (x, optional y)  // Required = 1, Optional = 1
    
  • Les arguments A sont compatibles avec la fonction F si les conditions suivantes sont remplies :

    • (N >= Fixed) et (N <= (Fixed + Optional))
    • Les types d’arguments sont compatibles avec les types de paramètres correspondants de F
  • Si la fonction a un type de retour déclaré, la valeur de résultat du corps de la fonction F est compatible avec le type de retour de F si la condition suivante est remplie :

    • La valeur obtenue en évaluant le corps de la fonction avec les arguments fournis pour les paramètres de fonction a un type compatible avec le type de retour.
  • Si le corps de la fonction génère une valeur incompatible avec le type de retour de la fonction, une erreur avec le code de raison "Expression.Error" est générée.

Fonctions récursives

Pour écrire une valeur de fonction récursive, il est nécessaire d’utiliser l’opérateur d’étendue (@) pour référencer la fonction dans son étendue. Par exemple, l’enregistrement suivant contient un champ qui définit la fonction Factorial, et un autre champ qui l’appelle :

[ 
    Factorial = (x) => 
                if x = 0 then 1 else x * @Factorial(x - 1), 
    Result = Factorial(3)  // 6 
]

De même, vous pouvez écrire des fonctions mutuellement récursives tant que chaque fonction devant être sollicitée a un nom. Dans l’exemple suivant, une partie de la fonction Factorial a été refactorisée en une deuxième fonction Factorial2.

[ 
    Factorial = (x) => if x = 0 then 1 else Factorial2(x), 
    Factorial2 = (x) => x * Factorial(x - 1), 
    Result = Factorial(3)     // 6 
]

Fermetures

Une fonction peut retourner une autre fonction en tant que valeur. Cette fonction peut à son tour dépendre d’un ou plusieurs paramètres de la fonction d’origine. Dans l’exemple suivant, la fonction associée au champ MyFunction retourne une fonction qui retourne le paramètre qui lui est spécifié :

[ 
    MyFunction = (x) => () => x, 
    MyFunction1 = MyFunction(1), 
    MyFunction2 = MyFunction(2), 
    Result = MyFunction1() + MyFunction2()  // 3 
]

Chaque fois que la fonction est appelée, une nouvelle valeur de fonction est retournée qui conserve la valeur du paramètre de sorte que, quand il est appelé, la valeur du paramètre est retournée.

Fonctions et environnements

En plus des paramètres, le function-body d’une function-expression peut référencer des variables qui sont présentes dans l’environnement quand la fonction est initialisée. Par exemple, la fonction définie par le champ MyFunction accède au champ C de l’enregistrement englobant A :

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

Quand MyFunction est appelée, elle accède à la valeur de la variable C, même si elle est appelée à partir d’un environnement (B) qui ne contient pas de variable C.

Déclarations simplifiées

each-expression est un raccourci syntaxique pour déclarer des fonctions non typées qui prennent un paramètre unique nommé _ (trait de soulignement).

each-expression:
      eacheach-expression-body
each-expression-body :
      function-body

Les déclarations simplifiées sont couramment utilisées pour améliorer la lisibilité de l’appel de fonction d’ordre supérieur.

Par exemple, les paires de déclarations suivantes sont sémantiquement équivalentes :

each _ + 1 
(_) => _ + 1  
each [A] 
(_) => _[A] 
 
Table.SelectRows( aTable, each [Weight] > 12 ) 
Table.SelectRows( aTable, (_) => _[Weight] > 12 )