Haskell/Soluções: diferenças entre revisões
[edição não verificada] | [edição não verificada] |
Conteúdo apagado Conteúdo adicionado
Adicionado →Casamento de padrões |
m <source> -> <syntaxhighlight> (phab:T237267) |
||
Linha 7:
# Defina uma função que subtraia 12 da metade de seu argumento.}}
#<
quadruplicar x = dobrar (dobrar x)
quadruplicar 5 = dobrar (dobrar 5)
quadruplicar 5 = dobrar 10
quadruplicar 5 = 20
</syntaxhighlight>
#<
subtrairMetade x = x / 2 - 12
</syntaxhighlight>
{{Exercícios|1=
Linha 21:
# Aproximadamente, de quantas pedras as famosas pirâmides de Gizé feitas? Dica: você vai precisar estimar o volume da pirâmide e o volume de cada bloco de pedra.}}
#<
#Uma possível solução para o problema da pirâmide seria: calcular o volume da pirâmide como se ela fosse ideal e dividir tal valor pelo volume estimado de um bloco de pedra. Por exemplo, no GHCi:
Linha 33:
# Escreva uma função que calcule o volume de um cilindro. O volume de um cilindro é a área da base, que é um círculo, multiplicada pela altura. Como você já programou a função da área de um círculo neste capítulo, você pode reutilizá-la aqui.}}
#<
area r = pi * r ^ 2
volumeCil r h = h * area r
</syntaxhighlight>
== [[Haskell/Tipos básicos|Tipos básicos]] ==
Linha 59:
}}
#<
negativo :: Int -> Int
</syntaxhighlight>
#<
(||) :: Bool -> Bool
</syntaxhighlight>
#<
diasNoMes :: Bool -> Int -> Int
</syntaxhighlight>
#<
f :: Int -> Int -> Bool
</syntaxhighlight>
#<
g :: Int -> Int
</syntaxhighlight>
== [[Haskell/Listas e n-uplas|Listas e n-uplas]] ==
Linha 92:
# Não. Todos os elementos de uma lista devem ser do mesmo tipo. Em <code>3:[rue,False]</code> tenta-se adicionar um número a uma lista de Bools, o que não é permitido.
# <
cons8 lista = 8:lista
</syntaxhighlight>
# <
cons8' lista = lista ++ [8]
</syntaxhighlight>
# <code> let meuCons lista elemento = elemento : lista</code>
Linha 181:
# Uma possível solução seria: <code>snd (fst (("Ola", 4), True))</code>.
# Sim, pois uma dupla permite que seus elementos sejam de qualquer tipo, ao contrário de uma lista que exige que todos os elementos sejam do mesmo tipo.
# <
cabecaCauda lista = (head lista, tail lista)
</syntaxhighlight>
#<
quintoElemento lista = head (tail (tail (tail (tail lista))))
</syntaxhighlight>
::Para criar a função <code>quintoElemento</code> precisamos repetir <code>tail</code> quatro vezes. Toda essa repetição deixa o código mais propenso a erros e mais difícil de ler.
Linha 199:
}}
# <
cabecaCauda :: [a] -> (a, [a])
</syntaxhighlight>
# <
quintoElemento :: [a] -> a
</syntaxhighlight>
# <
h :: Int -> a -> b -> Char -- y e z não são usados, portanto, seus tipos não importam e nem precisam ser iguais
</syntaxhighlight>
== [[Haskell/Casamento de padrões, if e let|Casamento de padrões, if e let]] ==
Linha 218:
Reescreva a função <code>pts</code> usando guardas.}}
<
pts :: Int -> Int
pts x
Linha 228:
| x == 6 = 1
| otherwise = 0
</syntaxhighlight>
{{Exercício|1=
Linha 239:
Uma possível solução seria escrever:
<
pts :: Int -> Int
pts 1 = 10
Linha 246:
| x < 1 || x > 7 = 0
| otherwise = 7 - x
</syntaxhighlight>
{{Exercício|1=
Linha 252:
}}
<
quarto :: (a,b,c,d,e,f,g,h,i,j) -> d
quarto (_,_,_,x,_,_,_,_,_,_) = x
</syntaxhighlight>
== [[Haskell/Entradas e saídas simples|Entradas e saídas simples]] ==
Linha 263:
Como abrir uma janela implica numa ação com consequências no ambiente externo, a saída de <code>abrirJanela</code> deve ser <code>IO</code>:
<
abrirJanela :: JanelaTitulo -> JanelaTamanho -> IO Janela
</syntaxhighlight>
{{Exercício|1=
Linha 285:
Você deve vai precisar usar as funções <code>read</code> e <code>show</code> para converter o texto do usário em número, e depois o resultado numérico em texto.}}
<
main :: IO ()
main =
Linha 294:
putStrLn ("A área do triângulo é " ++ show (area base altura) ++ ".")
where area b a = (read b :: Float) * (read a :: Float) / 2
</syntaxhighlight>
{{Exercício|1=
Linha 302:
}}
<
main :: IO ()
main =
Linha 312:
then putStrLn "Acredito que Haskell pode ser aprendido por qualquer pessoa!"
else putStrLn "Desculpe-me, não te conheço."
</syntaxhighlight>
Uma possível solução usando casamento de padrões:
<
main :: IO ()
main =
Linha 327:
resposta "Maria" = "Acredito que Haskell pode ser aprendido por qualquer pessoa!"
resposta _ = "Desculpe-me, não te conheço."
</syntaxhighlight>
= Introdutório =
Linha 337:
{{Exercício|1=
# O que acontece se calcularmos <code>fatorial (-1)</code>?
# Como já vimos antes, a ordem dos padrões é importante quando definimos uma função. Se fizéssemos <
fatorial n = n * fatorial (n - 1)
fatorial 0 = 1
</
# O ''fatorial duplo'' de um número é a multiplicação dos sucessores intercalados, partindo de 1 (ou 2) até o argumento. Por exemplo: o fatorial duplo de 8 é 8 × 6 × 4 × 2 = 384; o fatorial duplo de 7 é 7 × 5 × 3 × 1 = 105. Defina uma função <code>fatorialDuplo</code> em Haskell que faça esta conta.
}}
Linha 346:
# O compilador começaria a avaliar<br /><code>(-1) * fatorial (-2)</code><br /><code>(-1) * (-2) * fatorial (-3)</code><br /><code>(-1) * (-2) * (-3) * fatorial (-4)</code><br />e assim por diante. Como a definição de <code>fatorial</code> não possui nenhum caso que impeça essa expansão, o compilador começaria o processo mas nunca consegueria terminá-lo corretamente.
# O compilador avaliaria corretamente até <code>6 * 5 * 4 * 3 * 2 * 1 * fatorial 0</code>. Neste ponto, ele deveria encerrar a recursividade, mas como um argumento <code>0</code> satisfaz a condição do primeiro caso, o caso base nunca seria avaliado e a expansão do fatorial continuaria pelos números negativos. O resultado seria o mesmo que o do exercício anterior.
# <
fatorialDuplo 1 = 1
fatorialDuplo 2 = 2
fatorialDuplo n = n * fatorialDuplo (n - 2)
</syntaxhighlight>
{{Exercício|1=
Linha 358:
}}
# <
potencia _ 0 = 1
potencia x y = x * potencia x (y - 1)
</syntaxhighlight>
# <
adicao x 0 = x
adicao x y = adicao (maisUm x) (y - 1)
</syntaxhighlight>
# <
log2 1 = 0
log2 x = 1 + log2 (div x 2)
</syntaxhighlight>
=== Recrusividade usando listas ===
Linha 380:
# Redefina <code>length</code> usando uma função interna auxiliar e um parâmetro acumulador.}}
# <
replicar :: Int -> a -> [a]
replicar 0 _ = []
replicar n x = x : replicar (n - 1) x
</syntaxhighlight>
# <
(!!!) :: [a] -> Int -> a
(x:xs) !!! 0 = x
(x:xs) !!! n = xs !!! (n - 1)
</syntaxhighlight>
# <
ziper :: [a] -> [b] -> [(a,b)]
ziper [] _ = []
ziper _ [] = []
ziper (x:xs) (y:ys) = (x,y) : ziper xs ys
</syntaxhighlight>
# <
minhaLength :: [t] -> Int
minhaLength l = go l 0
where go [] n = n
go (x:xs) n = go xs (n+1)
</syntaxhighlight>
== [[Haskell/Listas II|Listas II]] ==
Linha 409:
Defina a função recursiva <code>repetir :: a -> [a]</code> que cria listas infinitas. O Prelude possui a <code>repeat</code> que realiza a mesma tarefa.}}
<
repetir :: a -> [a]
repetir x = x : repetir x
</syntaxhighlight>
Linha 431:
}}
# <
tomarInt :: Int -> [a] -> [a]
tomarInt _ [] = []
tomarInt 0 _ = []
tomarInt n (x:xs) = x : tomarInt (n - 1) xs
</syntaxhighlight>
# <
eliminarInt :: Int -> [a] -> [a]
eliminarInt _ [] = []
eliminarInt 0 xs = xs
eliminarInt n (x:xs) = eliminar (n - 1) xs
</syntaxhighlight>
# <
somarInt :: [Int] -> Int
somarInt [] = 0
somarInt (x:xs) = x + somarInt xs
</syntaxhighlight>
# <
scanSoma :: [Int] -> [Int]
scanSoma [] = []
Linha 460:
aux tot (x:xs) = tot' : aux tot' xs
where tot' = x + tot
</syntaxhighlight>
# <
difs [] = []
difs (x:[]) = []
Linha 471:
where aux _ [] = []
aux (a:as) (b:bs) = (b - a) : aux as bs
</syntaxhighlight>
== [[Haskell/Listas III|Listas III]] ==
Linha 487:
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.}}
# <
-- Versão recursiva
eListas :: [Bool] -> Bool
Linha 505:
ouListas' :: [Bool] -> Bool
ouListas' ls = foldr (||) False ls
</syntaxhighlight>
#
# <
maximo :: Ord a => [a] -> a
maximo = foldl1 max
Linha 513:
minimo :: Ord a => [a] -> a
minimo = foldl1 min
</syntaxhighlight>
#
# <
inverter :: [a] -> [a]
inverter ls = foldl consInvertido [] ls
where consInvertido xs x = x : xs
</syntaxhighlight>
=== ''Scans'' ===
Linha 528:
}}
# <
-- Versão recursiva
scanR :: (a -> b -> b) -> b -> [a] -> [b]
Linha 550:
scanL' f acum [] = [acum]
scanL' f acum ls = (scanL' f acum (init ls)) ++ [foldl f acum ls]
</
#
# <
fatLista :: Int -> [Int]
fatLista n = scanl (*) 1 [2..n]
</syntaxhighlight>
=== Compreensão de listas ===
Linha 571:
}}
# <
retornaDivisiveis :: Int -> [Int] -> [Int]
retornaDivisiveis n xs = [x | x <- xs, mod x n == 0]
</syntaxhighlight>
#
# <
selecionaCaudas :: [[Int]] -> [[Int]]
selecionaCaudas ls = [xs | (x:xs) <- ls, x > 5]
</syntaxhighlight>
#
# 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.
#
# <
mapear :: (a -> b) -> [a] -> [b]
mapear f xs = [f x | x <- xs]
Linha 589:
filtrar :: (a -> Bool) -> [a] -> [a]
filtrar f xs = [x | x <- xs, f x]
</syntaxhighlight>
#
# <
fstComSndPar :: [(Int, Int)] -> [Int]
fstComSndPar ls = (map fst . filter faux) ls
where faux (x,y) = ePar y
</syntaxhighlight>
== [[Haskell/Declaração de tipos|Declaração de tipos]] ==
Linha 607:
}}
<
data Data = Data Int Int Int -- ano, mês, dia
data Aniversario = Nascimento String Data -- nome, data
Linha 626:
romaoCasamento :: Aniversario
romaoCasamento = Casamento "João Romão" "Maria Romão" (Data 1987 3 4)
</syntaxhighlight>
Linha 632:
Reescreva a declarção de <tt>Aniversario</tt> usando o sinônimo <tt>Nome</tt>, e mantendo o uso de <tt>Data</tt>.}}
<
type Nome = String
data Data = Data Int Int Int -- ano, mês, dia
data Aniversario = Nascimento Nome Data -- nome, data
| Casamento Nome Nome Data -- nome 1, nome 2, Data
</syntaxhighlight>
Linha 644:
# Trantado-se de registros e dentro de um mesmo módulo, por que dois campos, de dois tipos diferentes, não podem ter o mesmo nome?}}
# <
data Data = Data {ano :: Int, mes :: Int, dia :: Int}
mostrarData :: Data -> String
mostrarData d = show (ano d) ++ "-" ++ show (mes d) ++ "-" ++ show (dia d)
</syntaxhighlight>
#
# Cada campo torna-se uma função de acesso. Sendo estas funções realacionadas as tipos distintos, suas assinaturas de tipos serão diferentes para cada caso. Entretanto, Haskell não permite que uma função tenha mais que uma assinatura de tipo. Em outras palavras, é impossível ter <code>campo1 :: Dado1 -> Int</code> e <code>campo1 :: Dado2 -> Int</code> no mesmo lugar, por exemplo.
Linha 659:
* <code>let f x y = read x + y in foldr f 1 xs</code>}}
* <
map (\x -> x * 2 + 3) xs
</syntaxhighlight>
* <
foldr (\x y -> read x + y) 1 xs
</syntaxhighlight>
{{Exercício|# Seções são açúcar sintático para expressões lambdas. Reescreva as seguintes seções na forma de lambdas determine seus tipos:
Linha 672:
#
# Teste as seguintes linhas no GHCi:
:: <
norma3D x y z = sqrt (x^2 + y^2 + z^2)
norma3D' a b = a `norma3D` b
</syntaxhighlight>
:: Se a notação infixa só pode ser usada com funções de dois argumentos, por que a definição de <code>norma3D'</code> é válida? Os resultados de <code>norma3D</code> e <code>norma3D'</code> serão sempre iguais? Dica: observe os tipos de cada uma das funções e lembre-se de ''[[Haskell/Listas II#Currying|currying]]''.}}
#
## <
(\x -> 4 + x) :: (Num a) => a -> a
</syntaxhighlight>
## <
(\xs -> elem 1 xs) :: [a] -> Bool
</syntaxhighlight>
## <
(\c -> notElem c "abc") :: Char -> Bool
</syntaxhighlight>
#
# A função <code>norma3D</code> possui três argumentos, portanto seu tipo é da forma <code>a -> a -> a -> a</code>. Como temos o efeito de ''currying'', podemos considerar que <code>norma3D</code> tem dois argumentos se pensarmos seu tipo como sendo <code>a -> a -> (a -> a)</code>, isto é, uma função de dois argumentos que retorna uma função de um argumento. Assim sendo, se usarmos a notação de ponto livre, isto é, omitindo o terceiro argumento, forçamos o ''currying'' e podemos usar a notação infixa. Portanto, <code>nomra3D' a b</code> é, repetindo, ''uma função de dois argumentos que retorna uma função de um argumento'', sendo que podemos usá-la com três argumentos, pois <code>(f m) n == f m n</code>. Também é fácil ver que os resultados serão sempre iguais se expandirmos a aplicação de <code>norma3D'</code>:
::<
(norma3D' a b) c
(a `norma3D` b) c
(norma3D a b) c
norma3D a b c
</syntaxhighlight>
== [[Haskell/Casamento de padrões|Casamento de padrões]] ==
Linha 704:
Qualquer valor aplicado a <code>h</code> sempre retorna <tt>True</tt>. A definição de <code>h</code> é:
<
h :: Int -> Bool
h k = True
h _ = False
</syntaxhighlight>
No primeiro caso, o padrão definido como <code>k</code> casa com qualquer valor de entrada. Portanto, o primeiro caso será sempre verdadeiro, o que faz com que <code>h</code> sempre retorne <tt>True</tt>. Assim sendo, não há nenhum valor que faça <code>h</code> retornar <tt>False</tt>.
|