Vinícius Hansen

Notas sobre Haskell

Funções recursivas

No Haskell não temos loops como for e while, em vez disso usamos funções recursivas, que são funções que no final de sua execução chamam elas mesmas de volta. Na verdade elas são muito parecidas com os loops de repetição.

Vamos fazer uma função que receba como parâmetro um inteiro n e retorne a soma dos números pares entre 0 e n.

Em uma linguagem imperativa como o C, a função ficaria mais ou menos assim:

int soma_pares(n) {
    int sum = 0;
    for (int i=0; i < n; i++){
        if (n % 2 == 0){
            sum += n;
        }
    }
    return sum;
}

Já em Haskell ela fica assim:

somaPares 0 = 0
somaPares n =
    if mod n 2 == 0 then n + somaPares (n - 1)
    else somaPares (n - 1)

Perceba que se a condição mod n 2 == 0 for atendida, o resultado da função será o valor n somado ao valor da próxima chamada da função que será somaPares (n - 1), o resultado vai acumulando até que o n seja igual a zero, que é o caso de parada.


Listas

Tipos

Estrutura

Operadores de lista

Funções com listas

tamanho :: [a] -> Int --declaração de tipo
tamanho [ ] = 0 --caso de parada
tamanho (x:xs) = 1 + tamanho xs
somatorio :: (Num a) -> [a] -> a
somatorio [ ] = 0
somatorio (x:xs) = x + somatorio xs
nprimeiros :: Int -> [a] -> [a]
nprimeiros 0 _ = [ ]
nprimeiros _ [ ] = [ ]
nprimeiros n (x:xs) = x : nprimeiros (n - 1) xs

Tuplas

primeiro (a, b) -> a
primeiro (x, y) = x
-- como não precisamos no valor de y podemos substituí-lo por um _
primeiro (x, _) = x
--funcionamento desejado
> zip' [1, 2, 3] "abcd"
[(1, 'a'), (2, 'b'), (3, 'c')]
--implementação
zip' :: [a] -> [b] -> [(a,b)]
zip' _ [] = [] --se um dos elementos for vazio retorne lista vazia
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y):zip' xs ys
unzip' :: [(a,b)] -> ([a], [b])
unzip' [] = ([], [])
unzip' ((x,y):xys) = x:fst (unzip' xys), y:snd (unzip' xys)

Um pouco (bem pouco) de cálculo λ

O cálculo lambda é composto de 3 elementos:

e ::= x
    | \x -> e --uma função que recebe x e devolve e
    | e1 e2

Nesse caso temos:

Alguns exemplos de funções:

\x -> (\y -> y) -- recebe 2 args e retorna o segundo
\x -> (\y -> x) -- recebe 2 args e retorna o primeiro
-- simplificando...
\x y -> y
\x y -> x

dica: sempre que ver um \ lembre-se do λ

Fold

A função fold tem duas variações: foldr e foldl, o que muda de uma para outra é o sentido em que a função é aplicada(e a ordem dos argumentos). Meu entendimento dessa função ainda é muito limitado, mas consegui fazer um contador com ela:

Essa função conta as palavras de um frase (na verdade ela conta os espaços em branco e subtrai 1 para assim chegar no valor correto). Perceba que eu utilizei a opação acc no foldr e apliquei uma condição para incrementar o contador.

contaPalavras :: (Num a) => [Char] -> a
count e (x:xs)= foldr (\x acc -> if e==x then acc+1 else acc ) 1 (x:xs)
contaPalavras (x:xs) = count ' ' (x:xs)

Funções High Order

em breve


Escrito por Vinícius Hansen