Haskell - Funções
As funções desempenham um papel importante em Haskell, pois é uma linguagem de programação funcional. Como outras linguagens, Haskell tem sua própria definição e declaração funcional.
A declaração da função consiste no nome da função e sua lista de argumentos junto com sua saída.
A definição de função é onde você realmente define uma função.
Vamos dar um pequeno exemplo de add função para entender esse conceito em detalhes.
add :: Integer -> Integer -> Integer --function declaration
add x y = x + y --function definition
main = do
putStrLn "The addition of the two numbers is:"
print(add 2 5) --calling a function
Aqui, declaramos nossa função na primeira linha e, na segunda linha, escrevemos nossa função real que receberá dois argumentos e produzirá uma saída do tipo inteiro.
Como a maioria das outras linguagens, Haskell começa a compilar o código do mainmétodo. Nosso código irá gerar a seguinte saída -
The addition of the two numbers is:
7
Correspondência de padrões
A correspondência de padrões é o processo de correspondência de tipos específicos de expressões. Não é nada além de uma técnica para simplificar seu código. Essa técnica pode ser implementada em qualquer tipo de classe de tipo. If-Else pode ser usado como uma opção alternativa de correspondência de padrões.
O casamento de padrões pode ser considerado uma variante do polimorfismo dinâmico onde, em tempo de execução, diferentes métodos podem ser executados dependendo de sua lista de argumentos.
Dê uma olhada no seguinte bloco de código. Aqui, usamos a técnica de correspondência de padrões para calcular o fatorial de um número.
fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
Todos nós sabemos calcular o fatorial de um número. O compilador começará a procurar uma função chamada "fato" com um argumento. Se o argumento não for igual a 0, o número continuará chamando a mesma função com 1 a menos que o argumento real.
Quando o padrão do argumento corresponder exatamente a 0, ele chamará nosso padrão, que é "fato 0 = 1". Nosso código produzirá a seguinte saída -
The factorial of 5 is:
120
Guardas
Guardsé um conceito muito semelhante ao casamento de padrões. Na correspondência de padrões, geralmente combinamos uma ou mais expressões, mas usamosguards para testar alguma propriedade de uma expressão.
Embora seja aconselhável usar correspondência de padrões sobre guards, mas da perspectiva de um desenvolvedor, guardsé mais legível e simples. Para usuários iniciantes,guards podem ser muito semelhantes às instruções If-Else, mas são funcionalmente diferentes.
No código a seguir, modificamos nosso factorial programa usando o conceito de guards.
fact :: Integer -> Integer
fact n | n == 0 = 1
| n /= 0 = n * fact (n-1)
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
Aqui, nós declaramos dois guards, separados por "|" e chamando ofact função de main. Internamente, o compilador funcionará da mesma maneira que no caso de correspondência de padrões para produzir a seguinte saída -
The factorial of 5 is:
120
Cláusula Where
Whereé uma palavra-chave ou função embutida que pode ser usada em tempo de execução para gerar uma saída desejada. Pode ser muito útil quando o cálculo da função se torna complexo.
Considere um cenário em que sua entrada é uma expressão complexa com vários parâmetros. Nesses casos, você pode quebrar a expressão inteira em pequenas partes usando a cláusula "where".
No exemplo a seguir, estamos considerando uma expressão matemática complexa. Mostraremos como você pode encontrar as raízes de uma equação polinomial [x ^ 2 - 8x + 6] usando Haskell.
roots :: (Float, Float, Float) -> (Float, Float)
roots (a,b,c) = (x1, x2) where
x1 = e + sqrt d / (2 * a)
x2 = e - sqrt d / (2 * a)
d = b * b - 4 * a * c
e = - b / (2 * a)
main = do
putStrLn "The roots of our Polynomial equation are:"
print (roots(1,-8,6))
Observe a complexidade de nossa expressão para calcular as raízes da função polinomial fornecida. É bastante complexo. Portanto, estamos quebrando a expressão usando owherecláusula. O trecho de código acima irá gerar a seguinte saída -
The roots of our Polynomial equation are:
(7.1622777,0.8377223)
Função de recursão
Recursão é uma situação em que uma função chama a si mesma repetidamente. Haskell não fornece nenhum recurso de loop de qualquer expressão por mais de uma vez. Em vez disso, Haskell quer que você divida sua funcionalidade inteira em uma coleção de funções diferentes e use a técnica de recursão para implementar sua funcionalidade.
Vamos considerar nosso exemplo de correspondência de padrões novamente, onde calculamos o fatorial de um número. Encontrar o fatorial de um número é um caso clássico de recursão. Aqui, você pode: "Como a correspondência de padrões é diferente da recursão?” A diferença entre esses dois está na maneira como são usados. A correspondência de padrões funciona na configuração da restrição de terminal, enquanto a recursão é uma chamada de função.
No exemplo a seguir, usamos a correspondência de padrões e a recursão para calcular o fatorial de 5.
fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )
main = do
putStrLn "The factorial of 5 is:"
print (fact 5)
Ele produzirá a seguinte saída -
The factorial of 5 is:
120
Função de ordem superior
Até agora, o que vimos é que as funções Haskell ocupam um type como entrada e produzir outro typecomo saída, que é muito semelhante em outras linguagens imperativas. Funções de ordem superior são um recurso exclusivo do Haskell onde você pode usar uma função como argumento de entrada ou saída.
Embora seja um conceito virtual, mas em programas do mundo real, cada função que definimos em Haskell usa um mecanismo de ordem superior para fornecer saída. Se você tiver a chance de examinar a função da biblioteca de Haskell, verá que a maioria das funções da biblioteca foi escrita em ordem superior.
Tomemos um exemplo em que importaremos um mapa de funções de ordem superior embutido e usaremos o mesmo para implementar outra função de ordem superior de acordo com nossa escolha.
import Data.Char
import Prelude hiding (map)
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map func (x : abc) = func x : map func abc
main = print $ map toUpper "tutorialspoint.com"
No exemplo acima, usamos o toUpper função da classe de tipo Charpara converter nossa entrada em maiúsculas. Aqui, o método "map" está tomando uma função como argumento e retornando a saída necessária. Aqui está o resultado -
sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts
sh-4.3$ main
"TUTORIALSPOINT.COM"
Expressão Lambda
Às vezes, temos que escrever uma função que será usada apenas uma vez, durante toda a vida útil de um aplicativo. Para lidar com esse tipo de situação, os desenvolvedores de Haskell usam outro bloco anônimo conhecido comolambda expression ou lambda function.
Uma função sem definição é chamada de função lambda. Uma função lambda é denotada pelo caractere "\". Tomemos o seguinte exemplo, onde aumentaremos o valor de entrada em 1 sem criar nenhuma função.
main = do
putStrLn "The successor of 4 is:"
print ((\x -> x + 1) 4)
Aqui, criamos uma função anônima que não possui um nome. Leva o inteiro 4 como argumento e imprime o valor de saída. Basicamente, estamos operando uma função sem nem mesmo declará-la adequadamente. Essa é a beleza das expressões lambda.
Nossa expressão lambda produzirá a seguinte saída -
sh-4.3$ main
The successor of 4 is:
5