Hoje o assunto é bem bacana, venho fazendo uma listinha de exercícios marotos em Scala, e estou aprendendendo muito. Hoje o assunto é recursividade, de novo esse assunto? Sim isso está mudando minha vida ou mesmo a forma como penso. (Exagerando rs)
Então, vamos fazer em Haskell?
A ideia é simples, quero deixar bem claro e simples as operações em listas imutáveis usando recursividade, já expliquei algo sobre listas imutáveis aqui.
Bom, vamos começar com um problema, que tal fazermos um map* em uma lista.
* = Para quem não sabe, mapear uma lista é transformar cada valor da lista atual, em um valor que passará através de uma determinada função.
Crie um novo arquivo, double.hs, como não falo há pouco de tempo de Haskell, nos meus primeiros posts, você consegue ver como instalar o interpretador Hugs.
Vamos ao double.hs:
double [] = []
double (head:tail) = head * 2 : double tail
Bom, isso aí já torna a compreensão pouco simples, mas vou explicar, entenda:
double [] = []
é a nossa guarda, ou seja, um ponto onde devemos parar a execução da função. Já falei muito a respeito em posts mais antigos.Já na segunda linha, vemos algo novo, mas acredito ser bem expressivo,
double (head:tail)
, ali estamos separando a cabeça da lista, de seu corpo, faremos uma operação na cabeça (head *2)
e concatenaremos com o corpo, mas passando o corpo como argumento da função double, repetiremos esse processo novamente, isso é incrível e simples.Para exercitar, primeiro vamos deixar nosso double mais genérico, pois podemos querer fazer outros tipos de map em lista, crie um arquivo mapear.hs:
mapear f [] = []
mapear f (x:xs) = (f x) : mapear f xs
Pronto, agora nossa função está apta a receber outras funções a serem aplicadas a lista, você pode testar no Hugs.
Vá ao seu terminal, caminhe até o diretório do arquivo e digite:
hugs mapear.hs
Para construir listas em Haskell, você pode usar de duas formas:
[1,1,2,3,5,8]
1 : 1 : 2 : 3 : 5 : 8 : []
Agora é só passar os parâmetros para sua função:
mapear (*2) (1 : 2 : 3 : [])
Use os parênteses para "separar" os argumentos. Tudo certo! (Ou deveria estar).Vamos evoluir mais um pouco, outra das operações básicas que podem ser efetuadas com lista é o Filter, onde você filtra os elementos da lista e só extraí o que "passar pelo filtro". Basicamente vamos passar uma validação para cada elemento da lista, e como fazer? Crie um arquivo filtro.hs e vamos codar nele:
filtro :: (a -> Bool) -> [a] -> [a]
filtro f [] = []
filtro f (x:xs) | f x = x : filtro f xs
| otherwise = filtro f xs
Trabalhamos com quase a mesma forma de aplicar a função do mapear, porém fizemos uma verificação, onde:
-
|
é a nossa verificação; - caso
f x
retorne false: - devolvemos só
filtro f xs;
- caso
f x
retorne true: - concatenamos a cabeça
x
aofiltro f xs
;
Ou seja, como vamos navegando na lista, cada hora a cabeça é o elemento posterior, isso é muito simples. Já falei de estruturas de verificação.
O desafio de hoje é meio trabalhoso, caso a preguiça domine vai ter que esperar eu fazer aqui também pra disponibilizar no Github. Você deve implementar um Flatten, ou seja, caso receba uma lista de listas, deve devolver uma lista contendo todos os elementos das listas internas.
É isso aí gente, qualquer dúvida comente abaixo ou email-me: abner.terribili@lambda3.com.br.