Funções F#

Este artigo será um guia prático para entender as funções e padrões do F# , bem como funções de ordem superior no F#.

Também exploraremos como o F# simplifica o processo de composição de funções para que comportamentos complexos possam ser criados. Você obterá uma sólida compreensão de como usar as funções do F#, independentemente de ser um novato na linguagem ou um programador experiente.

Os blocos de construção fundamentais de qualquer programa F# são funções que formam a base do programa.

O F# permite que as funções se comportem como cidadãos de primeira classe, dando a eles a capacidade de serem passados ​​como argumentos, usados ​​como valores e retornados como resultados usando o design de classe interno. Ao fazer isso, você pode escrever código de maneira altamente expressiva e concisa.

Há uma semelhança entre as funções do F# e os tipos de dados . Usar a função F# é como declarar uma variável como qualquer outra variável.

Você pode usar funções da mesma forma que pode usar outras variáveis, o que significa que você pode:

  • Descreva a função atribuindo um nome e um tipo associado a essa função.
  • Adicione um valor.
  • Com base nesse valor, faça alguns cálculos.
  • Um parâmetro pode ser passado de uma função ou sub-rotina para outra.
  • Pegar o resultado de alguma outra função e devolvê-lo como uma função.


Criação de função F#

Com a ajuda da palavra-chave let, as funções podem ser definidas. A sintaxe de uma definição de função é a seguinte:

let [inline] function-name parameter-list [ : return-type ]
= function-body

Onde,

  • F# Function-name refere-se ao identificador da função no programa.
  • A lista de parâmetros permite especificar uma lista de parâmetros separados por espaços. Se você não especificar nenhum tipo explícito para um parâmetro, o compilador deduzirá o tipo com base no corpo da função (o mesmo que faz com variáveis).
  • Um corpo de função é uma combinação de várias expressões ou uma expressão composta, que é construída a partir de várias expressões. A última expressão é o valor de retorno da função no corpo da função.
  • O tipo de retorno é um campo opcional que consiste em dois pontos seguidos por um tipo. No caso de uma função sem tipo de retorno especificado, o compilador tentará determiná-lo a partir da expressão final no corpo da função.

Parâmetros da Função F#

Os parâmetros de uma função F# são usados ​​para passar valores para a função na qual ela pode operar. De acordo com o problema específico que está sendo resolvido, os tipos e números de parâmetros necessários para uma função diferem dependendo da natureza do problema.

Não há limite para o número de parâmetros definidos dentro de uma função, e eles são declarados após o nome da função, separados por dois pontos.

Os parâmetros são tratados como variáveis ​​dentro da função, podendo ser utilizados para cálculos ou para tomada de decisões com base neles.

Assim que a função é chamada, os valores dos parâmetros são passados ​​para ela entre parênteses com um espaço entre eles. Deve haver uma correspondência entre a ordem dos valores e a ordem dos parâmetros na definição da função. Ao escrever código funcional em F#, é importante entender como os parâmetros funcionam e manipulá-los.

Um parâmetro pode ser especificado de acordo com seu tipo. O compilador infere o tipo de parâmetro se nenhum tipo for especificado.

Como um exemplo,

let rectangle(l : int, w: int) = l * w

Chamando uma função

Para chamar uma função, é necessário especificar o nome da função seguido de um espaço e depois os valores dos argumentos separados por espaços.

Como um exemplo,

let rect = rectangle 3 4,

Abaixo estão alguns exemplos de como esses conceitos podem ser demonstrados usando os seguintes programas.

Exemplo 1

O exemplo a seguir calcula a área de um quadrado usando as funções Fsharp:

Example: 

1
2
3
4
5
6
7
8
9
let rectangle length width : float =
// function body
length * width
let areaOfRect = rectangle 8.0 3.0
printfn " Area of Rectangular is: %g " areaOfRect
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
A seguinte saída do programa acima é:
Area of Rectangular is: 24

Exemplo 2

Existem dois parâmetros no programa a seguir que devem ser usados ​​para retornar o maior valor:

Example: 

1
2
3
4
5
6
7
8
9
10
11
let max num1 num2 : int32 =
// function body
if(num1>num2)then
num1
else
num2
let largest = max 14 2
printfn " Largest Value is: %d " largest
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Saída de exemplo de funções F#

Exemplo de Explicação

O exemplo acima define uma função max em F# que usa dois parâmetros inteiros num1 e num2 e retorna o valor máximo dos dois números. A função retorna int32 .

O corpo da função contém uma instrução if que verifica se num1 é maior que num2. Se num1 for maior que num2, a função retornará num1. Caso contrário, retorna num2.

Depois de definir a função max, o código a chama com os argumentos 14 e 2 para encontrar o maior valor entre os dois. O resultado é atribuído à variável maior.

Por fim, a função printfn é usada para imprimir uma mensagem que exibe o valor do maior.

Exemplo 3

Abaixo está um outro exemplo de quadratura do valor de 12:

Example: 

1
2
3
4
let square (x : int) = x * x
printfn "Square of %d: %d" 12 (square(12))
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

F# funções exemplo saída 2


Funções recursivas

Durante a execução de uma função recursiva em F#, a função chama a si mesma repetidamente. Muitas vezes, é útil usar funções recursivas na resolução de problemas onde é possível dividi-los em subproblemas menores e, em seguida, resolver recursivamente esses subproblemas menores.

Usando a combinação de palavra-chave let recursive, você pode definir um método recursivo.

Funções recursivas são definidas pela seguinte sintaxe:

//Recursive function definition
let rec function-name parameter-list = recursive-function-body

Por exemplo:

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)

Exemplo 1

Este é um exemplo de como você pode calcular o fatorial de um número usando funções recursivas em F#:

Example: 

1
2
3
4
5
6
7
let rec factorial n =
if n = 0 then 1
else n * factorial (n1)
printfn "Factorial of 5 is: %d" (factorial(5))
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

A seguir está uma saída do exemplo acima:

Factorial of 5 is: 120

Exemplo 2

O exemplo a seguir imprime a soma de n números adicionando 1 extra usando uma função recursiva:

Example: 

1
2
3
4
5
6
7
8
let rec sumNumber n accumlator=
// accumulator add integar by extra 1
if n = 0 then accumlator
else sumNumber (n-1)(n+accumlator)
printfn "The sum of first 8 itegers is: %A" (sumNumber 8 1)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

A saída do exemplo acima é a seguinte:

The sum of first 8 integers is: 37

Exemplo 3

Aqui está um programa que retorna números de Fibonacci de 1 a 5 usando uma função recursiva:

Example: 

1
2
3
4
5
6
7
8
let rec fib n =
if n <= 1 then n
else fib (n1) + fib (n2)
for i = 1 to 5 do
printfn "Fibonacci series on %d is: %d" i (fib i)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Após a execução do programa o exemplo acima imprime o seguinte resultado:

Fibonacci series on 1 is: 1
Fibonacci series on 2 is: 1
Fibonacci series on 3 is: 2
Fibonacci series on 4 is: 3
Fibonacci series on 5 is: 5

Exemplo de Explicação

O exemplo acima define uma função recursiva fib em F# que calcula o enésimo número na sequência de Fibonacci . A sequência de Fibonacci é uma série de números onde cada número é a soma dos dois números anteriores. Os dois primeiros números da sequência são 0 e 1.

A função fib recebe um parâmetro inteiro n e usa um algoritmo recursivo para calcular o n-ésimo número na sequência de Fibonacci. Se n for menor ou igual a 1, a função retornará n como resultado. Caso contrário, ele chama a si mesmo recursivamente com n – 1 e n – 2 como argumentos e retorna a soma dos dois resultados.

A segunda parte do código é um loop que imprime os primeiros 5 números na sequência de Fibonacci usando a função printfn . Ele chama a função fib com i como parâmetro para calcular o número i na sequência e imprime o resultado usando uma string formatada.


Notações de seta em F#

F# fornece informações de tipo de dados sobre funções e valores, usando notação de seta encadeada para relatar tipos de dados. Vamos dar um exemplo, no qual vamos pegar um int como entrada, e vamos retornar uma string como saída. Isso pode ser escrito em notação de seta como segue:

int -> string

Há uma ordem de leitura da esquerda para a direita para tipos de dados.

Tomando outra função hipotética como exemplo, podemos supor que ela recebe duas entradas inteiras e retorna uma string.

let intToString x y = (x / y).ToString();

O tipo de dados em F# é representado pela notação de seta encadeada da seguinte forma:

val intToString : x:int -> y:int -> string

O tipo de retorno é determinado pelo tipo de dados no ponto mais à direita da notação de seta encadeada.

Aqui estão mais alguns exemplos:

Notações Significado
flutuar → flutuar → flutuar Tomando duas entradas flutuantes, a função retorna outro flutuante com base nas entradas.
Int → String → flutuante Existe uma função que recebe um inteiro e uma string de entrada e retorna um valor flutuante.

Expressões Lambda

Ao usar expressões lambda em F#, você cria funções anônimas que serão colocadas diretamente em seu código como valores. As funções podem ser passadas como argumentos para outras funções ou representadas como dados na programação funcional.

Primeiro criamos a função como um método normal:

Example: 

1
2
3
4
5
6
7
let typeFunc( f: int -> int -> int) x y = f x y
let mul x y = x * y
let res = typeFunc mul 5 5
printfn "%d" res
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Alternativamente, poderíamos ter usado expressões lambda em vez de definir a função mul, como segue:

Example: 

1
2
3
4
5
6
let typeFunc ( f: int -> int -> int) x y = f x y
let res = typeFunc (fun x y -> x * y ) 5 5
printfn "%d" res
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Ambos os exemplos funcionam de maneira semelhante e imprimem a seguinte saída da seguinte maneira:

25

Veja a seguir outro exemplo de como imprimir a soma de três valores usando a função lambda:

Example: 

1
2
3
4
5
let someOfThree = (fun x y z -> x + y + z) 10 20 30
printfn "Sum is %d" someOfThree
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

A saída do exemplo acima é:

Sum is 60

Composição e Pipelining de Funções F#

O conceito de composição de função e pipelining é uma das técnicas comuns usadas por programadores funcionais para combinar funções em uma operação mais complexa.

Pipelining é um método de passar um valor por várias funções para fornecer um resultado final.

A composição de funções envolve o encadeamento de várias funções para produzir uma nova função.

O código pode se tornar mais conciso, modular, legível e compreensível usando ambas as técnicas.

Este exemplo demonstra como uma função denominada f pode ser criada a partir de duas funções denominadas função 1 e função 2 combinando os valores dessas duas funções em uma única função.

Example: 

1
2
3
4
5
6
7
8
9
10
let addTwo x = x + 2
let double x = x * 2
let addTwoThenDouble = double << addTwo
let result = addTwoThenDouble 3
printfn "Composition function result is: %d" result
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Depois de executar o exemplo, ele imprime da seguinte forma:

Composition function result is: 10

Há também um recurso especial no F# que permite o pipelining de funções. Usando o método de pipelining, as funções podem ser encadeadas para que possam ser executadas sequencialmente.

Aqui está um exemplo de como o pipelining funciona:

Example: 

1
2
3
4
5
6
7
8
9
let addTwo x = x + 2
let double x = x * 2
let result= 5 |> addTwo|> double
printfn "Pipelining result is: %d" result
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

A saída do código acima é a seguinte:

Pipelining result is: 14

Exemplo de Explicação

Neste código, primeiro definimos duas funções addTwo e double que pegam um único argumento x e executam alguma operação matemática nele.

Em seguida, usamos o operador |> , que é o operador de canal direto, para aplicar as funções addTwo e double ao valor 5. O operador de canal direto pega o valor no lado esquerdo e o passa como argumento para a função no lado direito. Portanto, 5 |> addTwo passa 5 como argumento para addTwo, que retorna 7. Então, 7 |> double passa 7 como argumento para double, que retorna 14.

Finalmente, atribuímos o resultado da composição da função a uma variável chamada resultado. Nesse caso, o resultado é 14. Em seguida, usamos printfn para imprimir o valor do resultado no console.

Se você gostou deste artigo e o achou informativo sobre a linguagem de programação funcional F#, você pode deixar seu feedback reagindo abaixo.

Nós valorizamos o seu feedback.
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0

Assine a nossa newsletter
Digite seu e-mail para receber um resumo semanal de nossos melhores posts. Saber mais!
ícone