Funções (F#)
As funções são a unidade fundamental de execução do programa em qualquer linguagem de programação. Como em outras linguagens, uma função de F# tem um nome, pode ter parâmetros e receber argumentos, e tem um corpo. F# também suporta construtores funcionais de programação como manipular funções como valores, usando funções sem nome em expressões, composição das funções para formar novas funções, funções surradas, e a definição implícita das funções pelo aplicativo parcial de argumentos de função.
Você define funções usando a palavra-chave de let , ou, se a função é recursivo, a combinação de palavras-chave de let rec .
// Non-recursive function definition.
let [inline] function-name parameter-list [ : return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body
Comentários
function-name é um identificador que representa a função. parameter-list sucessivos que consiste nos parâmetros são separados por espaços. Você pode especificar um tipo explícito para cada parâmetro, conforme descrito na seção de parâmetros. Se você não especificar um determinado tipo de argumento, o compilador tenta inferir o tipo do corpo da função. function-body consiste em uma expressão. A expressão que compõem o corpo da função é normalmente uma expressão composto que consiste em um número de expressões que culminam em uma expressão final que é o valor de retorno. return-type é dois-pontos seguidos por um tipo e é opcional. Se você não especificar o tipo do valor de retorno explicitamente, o compilador determina o tipo de retorno da expressão final.
Uma definição de função simples é parecida com o seguinte:
let f x = x + 1
No exemplo anterior, o nome da função é f, o argumento é x, que tem o tipo int, o corpo da função é x + 1, e o valor de retorno é do tipo int.
O especificador in-line é uma dica para o compilador que a função é pequena e que o código para a função pode ser integrado no corpo do chamador.
Escopo
A nenhum nível de escopo diferente do escopo de módulo, não é um erro para reutilizar um nome de valor ou função. Se você reutilizando um nome, o nome declarado como que posteriores o nome declarado anteriormente. No entanto, no escopo de alto nível em um módulo, os nomes devem ser exclusivos. Por exemplo, o código a seguir gera um erro quando aparece no escopo de módulo, mas não quando aparecer dentro de uma função:
let list1 = [ 1; 2; 3]
// Error: duplicate definition.
let list1 = []
let function1 =
let list1 = [1; 2; 3]
let list1 = []
list1
Mas o código a seguir é aceitável em qualquer nível de escopo:
let list1 = [ 1; 2; 3]
let sumPlus x =
// OK: inner list1 hides the outer list1.
let list1 = [1; 5; 10]
x + List.sum list1
Parâmetros
Os nomes dos parâmetros são listados após o nome da função. Você pode especificar um tipo para um parâmetro, conforme mostrado no exemplo o seguir:
let f (x : int) = x + 1
Se você especificar um tipo, siga o nome do parâmetro e é separado do nome por dois-pontos. Se você omitir o tipo para o parâmetro, o tipo de parâmetro é inferido pelo compilador. Por exemplo, a seguinte definição de função, o argumento x é inferido para ser do tipo int porque 1 é do tipo int.
let f x = x + 1
No entanto, o compilador tente fazer a função tão genérico quanto possível. Por exemplo, observe o seguinte código:
let f x = (x, x)
A função cria um tuple de um argumento de qualquer tipo. Porque o tipo não for especificado, a função pode ser usada com qualquer tipo de argumento. Para obter mais informações, consulte Generalização automática (F#).
Corpo da função
Um corpo da função pode conter definições de variáveis locais e funções. Tais variáveis e funções estão no escopo no corpo da função atual mas não de fora. Quando você tem a opção leve de sintaxe ativada, você deve usar o recuo para indicar que uma definição é em um corpo da função, conforme mostrado no exemplo o seguir:
let cylinderVolume radius length =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
Para obter mais informações, consulte Diretrizes de formatação de código (F#) e Sintaxe detalhada (F#).
Valores de retorno
O compilador usa a expressão final em um corpo da função para determinar o valor de retorno e o tipo. O compilador pode inferir o tipo da expressão final de expressões anteriores. Na função cylinderVolume, mostrada na seção anterior, o tipo de pi é determinado tipo de 3.14159 literal ser float. O compilador usa o tipo de pi para determinar o tipo da expressão h * pi * r * r ser float. Como consequência, o tipo de retorno total de função é float.
Para especificar explicitamente o valor de retorno, escreva o código seguinte maneira:
let cylinderVolume radius length : float =
// Define a local value pi.
let pi = 3.14159
length * pi * radius * radius
Enquanto o código é escrito anterior, o compilador aplica float a função inteira; se você significa o também aplicar aos tipos de parâmetro, use o seguinte código:
let cylinderVolume (radius : float) (length : float) : float
Chamando uma função
Você chama funções especificando o nome de função seguido por um espaço e em todos os argumentos separados por espaços. Por exemplo, para chamar a função cylinderVolume e atribuir o resultado ao valor vol, você escreve o código a seguir:
let vol = cylinderVolume 2.0 3.0
Aplicativo parcial de argumentos
Se você fornecer menor que o número especificado de argumentos, você cria uma nova função que espera argumentos restantes. Este método de argumentos de tratamento é conhecido como o surramento e é uma característica de linguagens de programação e como F#. Por exemplo, suponha que você estiver trabalhando com dois tamanhos de pipe: um tem um raio de 2.0 e o outro tem um raio de 3.0. Você pode criar funções que determinam o volume de pipe como segue:
let smallPipeRadius = 2.0
let bigPipeRadius = 3.0
// These define functions that take the length as a remaining
// argument:
let smallPipeVolume = cylinderVolume smallPipeRadius
let bigPipeVolume = cylinderVolume bigPipeRadius
Você forneceria no argumento adicional quando necessário para vários tamanhos de pipe dos tamanhos diferentes:
let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2
Funções recursivos
As funções recursivos são as funções que se chamam. Exigem que você especifica a palavra-chave de rec após a palavra-chave de let . Chamar a função recursiva de dentro do corpo da função exatamente como você invocaria qualquer chamada de função. Função recursiva a seguir calcula o número de Fibonacci de th de em. A sequência do número de Fibonacci foi conhecida como a antiguidade e é uma sequência em que cada são número é a soma de dois números anteriores em sequência.
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
Algumas funções recursivas podem transbordar a pilha do programa ou se você não puder executar as escreve cuidadosamente e com reconhecimento de técnicas especiais, como o uso de acumuladores e de continuações.
Valores de função
Em F#, todas as funções são consideradas valores; na verdade, são conhecidos como valores de função. Como as funções são valores, podem ser usadas como argumentos para outras funções ou outros contextos onde os valores são usados. A seguir está um exemplo de uma função que recebe um valor de função como um argumento:
let apply1 (transform : int -> int ) y = transform y
Você especifica o tipo de um valor de função usando o símbolo de -> . No lado esquerdo deste token é o tipo de argumento, e no lado direito é o valor de retorno. No exemplo anterior, apply1 é uma função que recebe uma função transform como um argumento, onde transform é uma função que recebe um número inteiro e retorna um inteiro outro. O código a seguir mostra como usar apply1:
let increment x = x + 1
let result1 = apply1 increment 100
O valor de result será 101 após o código anterior é executado.
Os argumentos são separados por vários tokens sucessivos de -> , conforme mostrado no exemplo o seguir:
let apply2 ( f: int -> int -> int) x y = f x y
let mul x y = x * y
let result2 = apply2 mul 10 20
O resultado é 200.
Expressões Lambda
Uma expressão lambda é uma função sem nome. Nos exemplos anteriores, em vez de definir funções increment nomeados e mul, você pode usar expressões lambda como segue:
let result3 = apply1 (fun x -> x + 1) 100
let result4 = apply2 (fun x y -> x * y ) 10 20
Você define expressões lambda usando a palavra-chave de fun . Uma expressão lambda lembra a uma definição de função, exceto que em vez do token de = , o símbolo de -> é usado para separar a lista de argumentos de corpo da função. Como em uma definição de função normal, os tipos de argumentos podem ser inferidos ou especificado explicitamente, e o tipo de retorno da expressão lambda é inferido do tipo da expressão a última no corpo. Para obter mais informações, consulte Expressões lambda: a palavra-chave fun (F#).
Composição de função e encanamento
Funções em F# podem ser compostos de outras funções. A composição de duas funções function1 e function2 é outra função que representa o aplicativo de function1 siga o aplicativo de function2:
let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100
O resultado é 202.
O encanamento permite que as chamadas de função a ser encadeadas juntos como operações sucessivas. Canalizar funciona como segue:
let result = 100 |> function1 |> function2
O resultado é novamente 202.
Operadores de composição têm duas funções e retornam uma função; por outro lado, os operadores de pipeline têm uma função e um argumento e retorna um valor. O exemplo de código a seguir mostra a diferença entre a pipeline e os operadores de composição mostrando as diferenças em assinaturas e uso da função.
// Function composition and pipeline operators compared.
let addOne x = x + 1
let timesTwo x = 2 * x
// Composition operator
// ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
let Compose2 = addOne >> timesTwo
// Backward composition operator
// ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
let Compose1 = addOne << timesTwo
// Result is 5
let result1 = Compose1 2
// Result is 6
let result2 = Compose2 2
// Pipelining
// Pipeline operator
// ( <| ) : ('T -> 'U) -> 'T -> 'U
let Pipeline1 x = addOne <| timesTwo x
// Backward pipeline operator
// ( |> ) : 'T1 -> ('T1 -> 'U) -> 'U
let Pipeline2 x = addOne x |> timesTwo
// Result is 5
let result3 = Pipeline1 2
// Result is 6
let result4 = Pipeline2 2
Sobrecarga de funções
Você pode sobrecarregar métodos de um tipo mas não de funções. Para obter mais informações, consulte Métodos (F#).