No último post você viu um exemplo de uma função para calcular o fatorial de um número.
Agora, continuando no tópico de funções, veremos mais alguns conceitos.
Primeiramente, você viu que foi especificado o tipo da função fatorial, que era Int -> Int, ou seja, uma função que recebe um inteiro e retorna um inteiro.
Agora, vejamos outra função:
soma :: Int -> Int -> Int
soma a b = a + b
Como o nome nos diz, essa função retorna a soma de seus dois argumentos.
Vamos começar a ver alguns de seus detalhes.
A primeira coisa que deve ser notada é que esta é uma função pura. ou seja, ela não faz alteração de nenhum estado e seu valor de retorno depende unicamente de seus valores de entrada.
“Mas você não havia dito que linguagens funcionais não guardam estado? Então todas as funções são puras?”
Não exatamente. Para conflitar com isso, vejamos, por exemplo, uma função que retorne um número aleatório. Normalmente estas não recebem nenhum parâmetro, mas retornam resultados variados. Então esse tipo de função não é pura.
Outro exemplo de funções impuras são funções que realizam operações de entrada e saída.
Outra coisa que deve ser notada é a declaração do tipo da função: Int -> Int -> Int. Isso não parece com algo que receba dois inteiros e retorne outro. E realmente não é isso.
Se você olhar a origem das linguagens funcionais, verá que são uma evolução do Cálculo Lambda, e uma de suas características é que as funções são unárias, ou seja, recebem apenas um argumento.
Voltemos ao fato de que funções são tipos de “alta ordem” em linguagens funcionais. Isso quer dizer que funções podem ser passadas como argumentos, ou podem ser retornadas de outros funções.
Na verdade, o que acontece é exatamente isso, em uma técnica chamada currying. O que ocorre realmente é que a função soma recebe apenas um argumento, retorna uma função que recebe mais um argumento e que, aí sim, retorna o resultado: Int -> (Int -> Int).