Compartilhar via


Funções

Uma função é um valor que representa um mapeamento de um conjunto de valores de argumento para um valor. Uma função é invocada por um conjunto de valores de entrada (os valores de argumento) fornecido e produz um valor de saída (o valor retornado).

Escrita de funções

As funções são gravadas usando uma expressão-de-função:

expressão-de-função:
      ( listade parâmetros opt)function-return-typeopt=>function-body
corpo-da-função:
      expressão
lista-de-parâmetros:
      lista-de-parâmetros-fixos
      lista
, de parâmetros fixos lista de parâmetros opcionais
      lista-de-parâmetros-opcionais
lista-de-parâmetros-fixos:
      parâmetro
      parâmetro
, lista de parâmetros fixos
parameter:
      nome-do-parâmetro tipo-de-parâmetroopcional
nome-do-parâmetro:
      identificador
tipo-de-parâmetro:
      assertion
tipo-de-retorno-da-função:
      assertion
declaração:

      as tipo de primiitve anulável
lista-de-parâmetros-opcionais:
      parâmetro-opcional
      parâmetro-opcional
, lista-de-parâmetros-opcionais
parâmetro-opcional:

      optionalparâmetro
tipo-primitivo-anulável
      nullable
opt do tipo primitivo

Veja a seguir um exemplo de uma função que requer exatamente dois valores x e y e produz o resultado da aplicação do operador + a esses valores. x e y são parâmetros que fazem parte da parameter-list da função, e x + y é o function-body:

(x, y) => x + y

O resultado da avaliação de uma expressão-de-função é produzir um valor de função (não avaliar o corpo-da-função). Como uma convenção neste documento, os valores de função (e não as expressões de função) são mostrados com a parameter-list, mas com reticências (...) em vez de com o function-body. Por exemplo, depois que a expressão de função acima tiver sido avaliada, ela será mostrada como o seguinte valor de função:

 (x, y) => ...

Os seguintes operadores são definidos para valores de função:

Operador Resultado
x = y Igual
x <> y Diferente

O tipo nativo de valores de função é um tipo de função personalizada (derivado do tipo intrínseco function) que lista os nomes de parâmetro e especifica todos os tipos de parâmetro e o tipo de retorno para any. (Acesse Tipos de função para obter detalhes sobre os tipos de função.)

Invocação de funções

O function-body de uma função é executado por meio da invocação do valor da função usando uma invoke-expression. Invocar um valor de função significa que o corpo-da-função do valor da função é avaliado e um valor é retornado ou um erro é gerado.

expressão-de-invocação:
      opção de lista de argumentos de expressão
(primária )
lista-de-argumentos:
      lista-de-expressões

Cada vez que um valor de função é invocado, um conjunto de valores é especificado como uma lista-de-argumentos, também chamados de argumentos para a função.

Uma lista-de-argumentos é usada para especificar um número fixo de argumentos diretamente como uma lista de expressões. O seguinte exemplo define um registro com um valor de função em um campo e, em seguida, invoca a função de outro campo do registro:

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

Os seguintes preceitos são válidos ao invocar uma função:

  • O ambiente usado para avaliar o corpo-da-função da função inclui uma variável que corresponde a cada parâmetro, com o mesmo nome que o parâmetro. O valor de cada parâmetro corresponde a um valor criado com base na argument-list da invoke-expression, conforme definido em Parâmetros.

  • Todas as expressões correspondentes aos argumentos da função são avaliadas antes que o corpo-da-função seja avaliado.

  • Os erros gerados ao avaliar as expressões na expression-list ou no function-body são propagados.

  • O número de argumentos criados com base na argument-list deve ser compatível com os parâmetros da função. Caso contrário, um erro será gerado com o código de motivo "Expression.Error". O processo para determinar a compatibilidade é definido em Parâmetros.

Parâmetros

Há dois tipos de parâmetros que podem estar presentes em uma parameter-list:

  • Um parâmetro obrigatório indica que um argumento correspondente ao parâmetro precisa sempre ser especificado quando uma função é invocada. Os parâmetros obrigatórios precisam ser especificados primeiro na parameter-list. A função neste exemplo define os parâmetros necessários x e y:

      [ 
          MyFunction = (x, y) => x + y, 
    
          Result1 = MyFunction(1, 1),     // 2 
          Result2 = MyFunction(2, 2)      // 4
      ] 
    
  • Um parâmetro opcional indica que um argumento correspondente ao parâmetro pode ser especificado quando uma função é invocada, mas não obrigatoriamente. Se um argumento que corresponder a um parâmetro opcional não for especificado quando a função for invocada, o valor null será usado. Os parâmetros opcionais devem aparecer após qualquer parâmetro obrigatório em uma parameter-list. A função neste exemplo define um parâmetro fixo x e um parâmetro opcional 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
      ] 
    

O número de argumentos especificados quando uma função é invocada deve ser compatível com a lista de parâmetros. A compatibilidade de um conjunto de argumentos A para uma função F é calculada da seguinte maneira:

  • Permita que o valor N represente o número de argumentos A criados com base na argument-list. Por exemplo:

      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
    
  • Deixe o valor Required representar o número de parâmetros fixos de F e Optional representar o número de parâmetros opcionais de F. Por exemplo:

    ()               // Required = 0, Optional = 0 
    (x)              // Required = 1, Optional = 0 
    (optional x)     // Required = 0, Optional = 1 
    (x, optional y)  // Required = 1, Optional = 1
    
  • Os argumentos A serão compatíveis com a função F se as seguintes condições forem verdadeiras:

    • (N >= Fixo) e (N <= (Fixo + Opcional))
    • Os tipos de argumento são compatíveis com os tipos de parâmetro correspondentes do F
  • Se a função tiver um tipo de retorno declarado, o valor de resultado do corpo da função F será compatível com o tipo de retorno de Fse o seguinte for verdadeiro:

    • O valor produzido pela avaliação do corpo da função com os argumentos fornecidos para os parâmetros de função tem um tipo compatível com o tipo de retorno.
  • Se o corpo da função gerar um valor incompatível com o tipo de retorno da função, um erro com o código de motivo "Expression.Error" será gerado.

Funções recursivas

Para gravar um valor de função que é recursivo, é necessário usar o operador de escopo (@) para fazer referência à função dentro do escopo dela. Por exemplo, o seguinte registro contém um campo que define a função Factorial e outro campo que a invoca:

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

Da mesma forma, funções mutuamente recursivas podem ser gravadas, desde que cada função que precise ser acessada tenha um nome. No exemplo a seguir, parte da função Factorial foi refatorada em uma segunda função Factorial2.

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

Fechamentos

Uma função pode retornar outra função como um valor. Essa função pode, por sua vez, depender de um ou mais parâmetros da função original. No seguinte exemplo, a função associada ao campo MyFunction retorna uma função que retorna o parâmetro especificado para ela:

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

Cada vez que a função é invocada, um novo valor de função será retornado mantendo o valor do parâmetro, de modo que, quando a função for invocada, o valor do parâmetro será retornado.

Funções e ambientes

Além dos parâmetros, o corpo-da-função de uma expressão-de-função pode referenciar variáveis que estão presentes no ambiente quando a função é inicializada. Por exemplo, a função definida pelo campo MyFunction acessa o campo C do registro delimitador A:

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

Quando MyFunction é invocado, ele acessa o valor da variável C, embora ele esteja sendo invocado de um ambiente (B) que não contém uma variável C.

Declarações simplificadas

A each-expression é uma abreviação sintática para declarar funções não tipadas usando um único parâmetro chamado _ (sublinhado).

expressão-each:
      eachcada corpo de expressão
corpo-da-expressão-each:
      corpo-da-função

Declarações simplificadas são normalmente usadas para melhorar a legibilidade da invocação de uma função de ordem superior.

Por exemplo, os seguintes pares de declarações são semanticamente equivalentes:

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