Explorar funções

Concluído

É comum estar em uma situação em que o código parece repetitivo. Ele faz a mesma coisa em vários lugares ou apresenta apenas pequenas diferenças. Em situações como essas, pense em como fazer com que o código fique reutilizável. A maneira de lidar com essa situação é extrair essas expressões e criar uma ou mais funções. Uma função é um bloco de construção fundamental em várias linguagens de programação, assim como no F#.

Uma função

Uma função é uma referência nomeada com um corpo que consiste em uma ou mais expressões. Ela também pode ter parâmetros. Uma função começa com a palavra-chave let e o nome da função. Depois, há um operador de atribuição e, à direita desse operador, está o corpo da função.

Veja a sintaxe de uma função:

let <function name> <parameters> = <function body>

Um exemplo de função real, como mostrado com a sintaxe de exemplo anterior, é assim:

let add a b = a + b 

Neste exemplo, o nome da função é add e os parâmetros são a e b. O corpo da função adiciona os dois parâmetros, a+b, e retorna o resultado.

Valores retornados

Como você viu no primeiro exemplo, não há nenhuma palavra-chave return para indicar o que está sendo retornado. No F#, as informações na última linha de uma função é o que está sendo retornado. Considere esta função multilinha:

let addAndMultiply a b c = 
    let sum = a + b
    let product = sum * c
    product

Ao colocar product na última linha, você é informado sobre o que está sendo retornado. Então, como chamar uma função como essa?

Chamar uma função

Para chamar (ou invocar) uma função, use o nome da função e adicione os parâmetros que deseja passar para ela separados por um caractere de espaço. Por exemplo, para chamar a função addAndMultiply(), insira o seguinte código:

addAndMultiply 2 3 3 // 15

Para ver os resultados da função, você pode atribuí-la a uma variável ou imprimi-la diretamente, desta forma:

let sum = addAndMultiply 2 3 3
printfn "%i" sum
// OR
printfn "%i" (addAndMultiply 2 3 3)

Tipos inferidos

Vamos usar o código a seguir:

let add a b = a + b
let sum = add 2 2 
let concat = add "hello" "world" // will give compilation error

Esse código falha na última linha com a seguinte mensagem:

error FS0001: This expression was expected to have type
    'int'    
but here has type
    'string'    

O motivo da falha é que o F# já determinou qual tipo de parâmetro deve ser usado, nesse caso, ele optou por inteiro. O motivo pelo qual ele optou por inteiro foi devido às informações na segunda linha, let sum = add 2 2. A função add() foi usada de uma forma que declarou que o tipo de parâmetro era definitivamente inteiro.

Se a segunda linha não existisse, o código funcionaria:

let add a b = a + b
// let sum = add 2 2 
let concat = add "hello" "world" // will work

O compilador vê que o primeiro uso da função é feito com cadeias de caracteres e conclui que o tipo do parâmetro é cadeia de caracteres. Portanto, o contexto e o primeiro uso inferem o tipo.

Tipos explícitos

Há situações em que você deseja ser explícito quanto aos tipos de parâmetros a serem adotados e o que a função retornará. A especificação ajuda a legibilidade, mesmo que, provavelmente, isso não seja necessário para o compilador.

Veja a seguinte função como exemplo:

let convert a =
    int a

Para adicionar tipos a ela, adicione :<type>, desta forma:

let convert (a:string) =
    int a

O parâmetro agora tem o tipo string por meio do código let convert (a:string). Agora você pode ser ainda mais explícito, adicionando um tipo de retorno. Para fazer isso, adicione outro :<type> logo após o parâmetro:

let convert (a:string) :int =
    int a

Agora o parâmetro está entre parênteses, como mostrado em (a:string). O tipo de retorno é a última anotação :<type> a ser executada, que é :int. O F# é inteligente o bastante para entender a maioria dos cenários, mas às vezes você precisa ajudar o código sendo mais explícito. Outro benefício da adição de tipos é que fica mais fácil para que outros desenvolvedores entendam o que está acontecendo.