Condividi tramite


Funzioni

Una funzione è un valore che rappresenta un mapping da un set di valori di argomento a un valore singolo. Una funzione viene richiamata fornendo un set di valori di input (valori di argomento) e produce un singolo valore di output (valore restituito).

Scrittura di funzioni

Le funzioni vengono scritte usando un'espressione 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:
      parameter-name parameter-typeopt
parameter-name:
      identificatore
parameter-type:
      assertion
function-return-type:
      assertion
assertion:

      as nullable-primitive-type
optional-parameter-list:
      optional-parameter
      optional-parameter
, optional-parameter-list
optional-parameter:

      optional parameter
nullable-primitve-type
      nullable
opt primitive-type

Di seguito è riportato un esempio di una funzione che richiede esattamente due valori x e y e ha come risultato l'applicazione dell'operatore + a tali valori. x e y sono parametri che fanno parte dell'elenco parameter-list della funzione e x + y è il corpo della funzione function-body:

(x, y) => x + y

Il risultato della valutazione di function-expression è la generazione di un valore della funzione (non la valutazione di function-body). Per convenzione, in questo documento i valori della funzione (a differenza delle espressioni della funzione) vengono visualizzati con parameter-list, ma con i puntini di sospensione (...) invece che con l'elemento function-body. Se, ad esempio, l'espressione della funzione precedente è stata valutata, viene visualizzata come valore della funzione seguente:

 (x, y) => ...

Per i valori di funzione vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal

Il tipo nativo dei valori di funzione è un tipo funzione personalizzato (derivato dal tipo intrinseco function) che elenca i nomi dei parametri e specifica che tutti i tipi di parametro e il tipo restituito devono essere any. Per informazioni dettagliate sui tipi funzione, vedere Tipi funzione.

Chiamata di funzioni

L'elemento function-body di una funzione viene eseguito richiamando il valore della funzione tramite invoke-expression. Richiamare il valore di una funzione significa che l'elemento function-body del valore della funzione viene valutato e viene restituito un valore o generato un errore.

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

Ogni volta che il valore di una funzione viene richiamato, un set di valori viene specificato come argument-list e tali valori sono denominati argomenti della funzione.

Un argument-list viene usato per specificare un numero fisso di argomenti direttamente come elenco di espressioni. L'esempio seguente definisce un record con un valore di funzione in un campo e quindi richiama la funzione da un altro campo del record:

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

Quando si richiama una funzione, tenere presente quanto segue:

  • L'ambiente usato per valutare il function-body della funzione include una variabile corrispondente a ogni parametro, con lo stesso nome del parametro. Il valore di ogni parametro corrisponde a un valore costruito dall'argument-list di invoke-expression, come definito in Parametri.

  • Tutte le espressioni corrispondenti agli argomenti della funzione vengono valutate prima di function-body.

  • Gli errori generati durante la valutazione delle espressioni in expression-list o in function-body vengono propagati.

  • Il numero di argomenti costruiti da argument-list deve essere compatibile con i parametri della funzione, altrimenti viene generato un errore con codice motivo "Expression.Error". Il processo per determinare la compatibilità è definito in Parametri.

Parametri

Esistono due tipi di parametri che possono essere presenti in parameter-list:

  • Un parametro obbligatorio indica che un argomento corrispondente al parametro deve essere sempre specificato quando viene richiamata una funzione. I parametri obbligatori devono essere specificati per primi in parameter-list. La funzione nell'esempio seguente definisce i parametri obbligatori x e y:

      [ 
          MyFunction = (x, y) => x + y, 
    
          Result1 = MyFunction(1, 1),     // 2 
          Result2 = MyFunction(2, 2)      // 4
      ] 
    
  • Un parametro facoltativo indica che un argomento corrispondente al parametro può essere specificato quando viene richiamata una funzione, ma non è obbligatorio specificarlo. Se un argomento che corrisponde a un parametro facoltativo non viene specificato quando viene richiamata la funzione, viene invece usato il valore null. I parametri facoltativi devono essere visualizzati dopo eventuali parametri obbligatori in parameter-list. La funzione nell'esempio seguente definisce un parametro fisso x e un parametro facoltativo 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
      ] 
    

Il numero di argomenti specificati quando viene richiamata una funzione deve essere compatibile con l'elenco di parametri. La compatibilità di un set di argomenti A per una funzione F viene calcolata nel modo seguente:

  • Il valore N dovrà rappresentare il numero di argomenti A costruiti da argument-list. Ad esempio:

      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
    
  • Il valore Required dovrà rappresentare il numero di parametri fissi di F e Optional il numero di parametri facoltativi di F, Ad esempio:

    ()               // Required = 0, Optional = 0 
    (x)              // Required = 1, Optional = 0 
    (optional x)     // Required = 0, Optional = 1 
    (x, optional y)  // Required = 1, Optional = 1
    
  • Gli argomenti A sono compatibili con la funzione F se sono soddisfatte le condizioni seguenti:

    • (N >= Fixed) e (N <= (Fixed + Optional))
    • I tipi di argomento sono compatibili con i tipi di parametro corrispondenti di F
  • Se la funzione ha un tipo restituito dichiarato, il valore del risultato del corpo della funzione F è compatibile con il tipo restituito di F se è soddisfatta la condizione seguente:

    • Il valore restituito dalla valutazione del corpo della funzione con gli argomenti forniti per i parametri della funzione ha un tipo compatibile con il tipo restituito.
  • Se il corpo della funzione restituisce un valore incompatibile con il tipo restituito della funzione, viene generato un errore con il codice motivo "Expression.Error".

Funzioni ricorsive

Per scrivere un valore di funzione ricorsivo, è necessario usare l'operatore di ambito (@) per fare riferimento alla funzione all'interno dell'ambito. Il record seguente, ad esempio, contiene un campo che definisce la funzione Factorial e un altro campo che la richiama:

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

Analogamente, possono essere scritte funzioni ricorsive reciproche purché ogni funzione a cui è necessario accedere abbia un nome. Nell'esempio seguente è stato effettuato il refactoring della parte della funzione Factorial in una seconda funzione Factorial2.

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

Chiusure

Una funzione può restituire un'altra funzione come valore. Questa funzione può a sua volta dipendere da uno o più parametri per la funzione originale. Nell'esempio seguente la funzione associata al campo MyFunction restituisce una funzione che le restituisce il parametro specificato:

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

Ogni volta che la funzione viene richiamata, viene restituito un nuovo valore di funzione che gestisce il valore del parametro in modo che, quando viene richiamato, il valore del parametro venga restituito.

Funzioni e ambienti

Oltre ai parametri, il function-body di una function-expression può fare riferimento alle variabili presenti nell'ambiente quando la funzione viene inizializzata. Ad esempio, la funzione definita dal campo MyFunction accede al campo C del record di inclusione A:

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

Quando MyFunction viene richiamato, accede al valore della variabile C, anche se viene richiamato da un ambiente (B) che non contiene una variabile C.

Dichiarazioni semplificate

each-expression è un'abbreviazione sintattica per la dichiarazione di funzioni non tipizzate che accettano un singolo parametro denominato _ (carattere di sottolineatura).

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

Le dichiarazioni semplificate vengono comunemente usate per migliorare la leggibilità della chiamata di funzioni di ordine superiore.

Ad esempio, le coppie di dichiarazioni seguenti sono semanticamente equivalenti:

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