Haskell/Soluções: diferenças entre revisões

[edição não verificada][edição não verificada]
Conteúdo apagado Conteúdo adicionado
→‎Listas III: adicionado
Linha 416:
 
=== Generalizando ===
 
{{Exercício|1=
Escreva as seguintes funções e teste-as no GHCi. Não se esqueça das assinaturas de tipo.
Linha 470 ⟶ 471:
where aux _ [] = []
aux (a:as) (b:bs) = (b - a) : aux as bs
</source>
 
== [[Haskell/Listas III|Listas III]] ==
=== ''Folds'' ===
 
{{Exercícios|1=
# Defina as seguintes funções recursivas, e depois escreva uma definição usando <code>foldr</code> ou <code>foldl</code>:
#* <code>eListas :: [Bool] -> Bool</code>, que retorna <code>True</code> se uma lista de Bools contiver apenas <code>True</code>, ou <code>False</code>, caso contrário.
#* <code>ouListas :: [Bool] -> Bool</code>, que retorna <code>True</code> se pelo menos um elemento de uma lista de Bools for verdadeiro, ou <code>False</code>, caso contrário.
# Defina as seguintes funções usando <code>foldl1</code> ou <code>foldr1</code>:
#* <code>maximo :: Ord a => [a] -> a</code>, que retorna o elemento de maior valor de uma lista. Use a função <code>max :: Ord a => a -> a -> a</code>, que retorna seu argumento de maior valor.
#* <code>minimo :: Ord a => [a] -> a</code>, que retorna o elemento de menor valor de uma lista. Use a função <code>min :: Ord a => a -> a -> a</code>, que retorna seu argumento de menor valor.
# Use uma função ''fold'' (qual?) para definir <code>inverter :: [a] -> [a]</code>, a qual inverte a ordem dos elementos de uma lista.
 
As funções do Prelude <code>and</code>, <code>or</code>, <code>maximum</code> e <code>minimum</code> correspondem às quatro primeiras funções destes exercícios, respectivamente.}}
 
# <source lang="haskell">
-- Versão recursiva
eListas :: [Bool] -> Bool
eListas [] = True
eListas (x:xs) = x && eListas xs
 
-- Usando foldr
eListas' :: [Bool] -> Bool
eListas' ls = foldr (&&) True ls
 
-- Versão recursiva
ouListas [Bool] -> Bool
ouListas [] = False
ouListas (x:xs) = x || ouListas xs
 
-- Usando foldr
ouListas' :: [Bool] -> Bool
ouListas' ls = foldr (||) False ls
</source>
#
# <source lang="haskell">
maximo :: Ord a => [a] -> a
maximo = foldl1 max
 
minimo :: Ord a => [a] -> a
minimo = foldl1 min
</source>
#
# <source lang="haskell">
inverter :: [a] -> [a]
inverter ls = foldl consInvertido [] ls
where consInvertido xs x = x : xs
</source>
 
=== ''Scans'' ===
 
{{Exercícios|1=
# Escreva sua própria definição de <code>scanr</code>: primeiro, use recusrividade, e depois use <code>foldr</code>. Faça o mesmo para <code>scanl</code>.
# Defina a função <code>fatLista :: Integer -> [Integer]</code>, que retorna uma lista dos fatoriais de 1 até o valor de seu argumento. Por exemplo: <code>fatLista 4 = [1,2,6,24]</code>.
}}
 
# <source lang="haskell">
-- Versão recursiva
scanR :: (a -> b -> b) -> b -> [a] -> [b]
scanR f acum [] = [acum]
scanR f acum (x:xs) = f x (head ant) : ant
where ant = scanR f acum xs
 
-- Usando foldr
scanR' :: (a -> b -> b) -> b -> [a] -> [b]
scanR' f acum [] = [acum]
scanR' f acum (x:xs) = foldr f acum (x:xs) : scanR' f acum xs
 
---------------------------------
--Versão recursiva
scanL :: (b -> a -> b) -> b -> [a] -> [b]
scanL f acum [] = [acum]
scanL f acum (x:xs) = acum : scanL f (f acum x) xs
 
-- Usando foldl
scanL' :: (b -> a -> b) -> b -> [a] -> [b]
scanL' f acum [] = [acum]
scanL' f acum ls = (scanL' f acum (init ls)) ++ [foldl f acum ls]
</source> Vale notar que a <code>scanL'</code> (usando <code>foldl</code>) é menos eficiente que <code>scanL</code> (versão recursiva).
#
# <source lang="haskell">
fatLista :: Int -> [Int]
fatLista n = scanl (*) 1 [2..n]
</source>
 
=== Compreensão de listas ===
 
{{Exercícios|1=
# Escreva a função <code>retornaDivisiveis :: Int -> [Int] -> [Int]</code> que filtra uma lista de inteiros e retorna apenas os elementos que são divisíveis pelo seu primeiro argumento. Dica: <code>x</code> é divisível por <code>n</code> se <code>mod x n == 0</code>.
#
# Escreva a função <code><nowiki>selecionaCaudas :: [[Int]] -> [[Int]]</nowiki></code> usando compreensão de listas. Ela deve retornar a cauda das listas cujas cabeças são maiores que 5, e deve eliminar listas vazias: <br /><code><nowiki>selecionaCaudas [[7,6,3],[],[6,4,2],[9,4,3],[5,5,5]] = [[6,3],[4,2],[4,3]]</nowiki></code>
#
# A ordem das condições altera o resultado da função? Descubra usando as funções que você acabou de escrever.
#
# Vimos que compreensão de listas são combinações de <code>filter</code> e <code>map</code>, mas agora você deve fazer o caminho inverso: defina <code>mapear</code> e <code>filtrar</code> usando compreensão de listas.
#
# Reescreva <code>fstComSndPar</code> usando <code>filter</code> e <code>map</code> em vez de compreensão de listas.
}}
 
# <source lang="haskell">
retornaDivisiveis :: Int -> [Int] -> [Int]
retornaDivisiveis n xs = [x | x <- xs, mod x n == 0]
</source>
#
# <source lang="haskell">
selecionaCaudas :: [[Int]] -> [[Int]]
selecionaCaudas ls = [xs | (x:xs) <- ls, x > 5]
</source>
#
# Sim, a ordem importa. Todas as condições devem ser satisfeitas na ordem em que aparecem na compreensão: se tivermos cinco condições e segunda for falsa, a terceira, a quarta e a quinta não serão avaliadas.
#
# <source lang="haskell">
mapear :: (a -> b) -> [a] -> [b]
mapear f xs = [f x | x <- xs]
 
filtrar :: (a -> Bool) -> [a] -> [a]
filtrar f xs = [x | x <- xs, f x]
</source>
#
# <source lang="haskell">
fstComSndPar :: [(Int, Int)] -> [Int]
fstComSndPar ls = (map fst . filter faux) ls
where faux (x,y) = ePar y
</source>