Maratona de Haskell - Décimo Primeiro Dia - Parte 2

Fala pessoal!

Depois da revisão que fizemos anteriormente eu acho que é uma boa idea praticar com alguns exercícios. Eu trabalhei na lista chamada 99 questions. Resolvi os dez primeiros exercícios, vamos dar uma olhada em alguns deles:


Exercício Dois

A descrição do exercício é: Find the last but one element of a list.

E este o exemplo:

myButLast [1,2,3,4]
3

myButLast ['a'..'z']
'y'

Ok, como vimos no terceiro dia nós temos a função last para obter o último elemento de uma lista, mas aqui queremos o penúltimo elemento. Se temos uma lista como [1,2,3,4,5] nós queremos retornar o número 4. Para fazer isso temos algumas funções para nos ajudar, uma é a função reverse que reverte a ordem de uma lista. A outra é a função !! que retorna o elemento do index informado. Lembre que Haskell inicia a lista com o index 0. Se revertermos e obtermos o index 1 isso funcionará.

myButLast :: [a] -> a
myButLast xs = reverse xs !! 1


myButLast [1,2,3,4]
3

myButLast ['a'..'z']
'y'


Exercício Seis

A descrição do exercício é: Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).

E este o exemplo:

isPalindrome [1,2,3]
False


isPalindrome "madamimadam"
True


isPalindrome [1,2,4,8,16,8,4,2,1]
True

Este tem uma simples solução, mas é um famoso desafio inclusive em entrevistas de emprego. Nós somente necessitamos comparar a lista recebida com a mesma revertida.

isPalindrome :: (Eq a) => [a] -> Bool
isPalindrome xs = xs == reverse xs


isPalindrome [1,2,3]
False


isPalindrome "madamimadam"
True


isPalindrome [1,2,4,8,16,8,4,2,1]
True

Temos que prestar atenção que esta função implementa a type classes de igualdade.


Exercício Oito

A descrição do exercício é: Eliminate consecutive duplicates of list elements. If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.

E este o exemplo:

compress "aaaabccaadeeee"
"abcade"

Eu inicie usando uma função auxiliar que funcionou:

compress :: (Eq a) => [a] -> [a]
compress [] = []
compress (x:[]) = [x]
compress (x:xs) = x : (compress $ (cleanRepeated x xs))


cleanRepeated :: (Eq a) => a -> [a] -> [a]
cleanRepeated _ [] = []
cleanRepeated x (y:ys) = if x == y then cleanRepeated x ys else y : ys


compress "aaaabccaadeeee"
"abcade"

Mas a solução não estava boa o suficiente. Então combinando Guards e as-pattern a função tornou-se mais simples:

compress' :: (Eq a) => [a] -> [a]
compress' (x:xs@(y:_))
  | x == y = compress xs
  | otherwise = x : compress xs


compress "aaaabccaadeeee"
"abcade"


Exercício Nove

A descrição do exercício é: Pack consecutive duplicates of list elements into sublists. If a list contains repeated elements they should be placed in separate sublists.

E o exemplo:

pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
["aaaa","b","cc","aa","d","eeee"]

Nós já vimos as funções take e drop que recebem um número de elementos para pega-los ou apaga-los. Eles tem irmãos que são chamados takeWhile e dropWhile que recebem uma função ao invés de um número.

take 5 ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
"aaaab"


drop 5 ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
"ccaadeeee"


takeWhile (=='a') ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
"aaaa"


dropWhile (=='a') ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
"bccaadeeee"

Com essas funções é fácil resolver o problema:

pack :: (Eq a) => [a] -> [[a]]
pack [] = []
pack (x:xs) = (x: takeWhile (==x) xs) : (pack $ dropWhile (==x) xs)


pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',  'a', 'd', 'e', 'e', 'e', 'e']
["aaaa","b","cc","aa","d","eeee"]



Estes são alguns exercício que eu suponho foram mais difíceis de resolver considerando o nosso conhecimento de Haskell. Nos próximos dias eu trabalharei em mais exercícios.

Written on December 11, 2016