Explorar funções
É 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 cujo corpo consiste de 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 são o que está sendo retornado. Considere a seguinte função de múltiplas linhas:
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. A razão pela qual ele decidiu pelo inteiro foi por causa das 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 :<type> anotação a acontecer, 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.