Exercícios MT1

Limpar todos os resolvidos?

Expressões, tipos e funções

Combinar dois geradoresEscolha múltipla

Qual o resultado de executar o seguinte código?

[(x,y) | x <- "abc", y <- [1,2]]
A tua resposta

Solução
Cada letra do primeiro gerador combina com os dois números, nessa ordem.
  • a. [('a',1), ('b',1), ('c',1), ('a',2), ('b',1), ('c',2)]. Esta alternativa não corresponde ao pedido. Cada letra do primeiro gerador combina com os dois números, nessa ordem.
  • b. [('a',1), ('b',2), ('a',1), ('b',2), ('a',1), ('b',2)]. Esta alternativa não corresponde ao pedido. Cada letra do primeiro gerador combina com os dois números, nessa ordem.
  • c. [('c',1), ('c',2), ('b',1), ('b',2), ('a',1), ('a',2)]. Esta alternativa não corresponde ao pedido. Cada letra do primeiro gerador combina com os dois números, nessa ordem.
  • d. [('a',1), ('a',2), ('b',1), ('b',2), ('c',1), ('c',2)]. Cada letra do primeiro gerador combina com os dois números, nessa ordem.
Voltar à explicação
Tipo de uma comparação mapeadaEscolha múltipla

Qual dos tipos é válido para a seguinte expressão?

(map (>0))
A tua resposta

Solução
O tipo principal é (Num a, Ord a) => [a] -> [Bool]. Int é uma especialização válida.
  • a. [Int] -> [Bool]. O tipo principal é (Num a, Ord a) => [a] -> [Bool]. Int é uma especialização válida.
  • b. [Char] -> [Bool]. Esta alternativa não corresponde ao pedido. O tipo principal é (Num a, Ord a) => [a] -> [Bool]. Int é uma especialização válida.
  • c. (Num a) => [a] -> Bool. Esta alternativa não corresponde ao pedido. O tipo principal é (Num a, Ord a) => [a] -> [Bool]. Int é uma especialização válida.
  • d. (Num a) => [a] -> [Bool]. Esta alternativa não corresponde ao pedido. O tipo principal é (Num a, Ord a) => [a] -> [Bool]. Int é uma especialização válida.
Voltar à explicação
Tipo do último elementoEscolha múltipla

Qual o tipo inferido pelo ghci para a seguinte função?

last [x] = x
last (x:xs) = last xs
A tua resposta

Solução
O resultado tem o tipo dos elementos. A função é parcial para a lista vazia.
  • a. [a] -> b. Esta alternativa não corresponde ao pedido. O resultado tem o tipo dos elementos. A função é parcial para a lista vazia.
  • b. [a] -> a. O resultado tem o tipo dos elementos. A função é parcial para a lista vazia.
  • c. (Num a) => [a] -> a. Esta alternativa não corresponde ao pedido. O resultado tem o tipo dos elementos. A função é parcial para a lista vazia.
  • d. [Int] -> Int. Esta alternativa não corresponde ao pedido. O resultado tem o tipo dos elementos. A função é parcial para a lista vazia.
Voltar à explicação
Somar com foldr e valor inicialEscolha múltipla

Qual o resultado de executar o seguinte código?

foldr (+) 7 [1,2,3]
A tua resposta

Solução
A redução é 1 + (2 + (3 + 7)) = 13.
  • a. [13]. Esta alternativa não corresponde ao pedido. A redução é 1 + (2 + (3 + 7)) = 13.
  • b. 6. Esta alternativa não corresponde ao pedido. A redução é 1 + (2 + (3 + 7)) = 13.
  • c. 7. Esta alternativa não corresponde ao pedido. A redução é 1 + (2 + (3 + 7)) = 13.
  • d. 13. A redução é 1 + (2 + (3 + 7)) = 13.
Voltar à explicação
Sinónimos e novos tiposEscolha múltipla
Considere as três afirmações seguintes sobre as diferenças entre type e data: A - Apenas data permite definições recursivas de tipos. B - Apenas data permite definições usando variáveis de tipo (type variables). C - Apenas data define novos padrões para pattern matching. Qual/Quais destas afirmações estão corretas?
A tua resposta

Solução
type aceita variáveis, mas não sinónimos recursivos. data introduz construtores para padrões.
  • a. Apenas B e C. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data introduz construtores para padrões.
  • b. A, B e C. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data introduz construtores para padrões.
  • c. Apenas A e B. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data introduz construtores para padrões.
  • d. Apenas A e C. type aceita variáveis, mas não sinónimos recursivos. data introduz construtores para padrões.
Voltar à explicação
Cabeça de uma lista de listasEscolha múltipla

Qual dos tipos é válido para a seguinte expressão?

head [[1], [2,3], [4,5,6]]
A tua resposta

Solução
O resultado é uma lista numérica; [Int] é uma especialização válida.
  • a. [Int]. O resultado é uma lista numérica; [Int] é uma especialização válida.
  • b. [a]. Esta alternativa não corresponde ao pedido. O resultado é uma lista numérica; [Int] é uma especialização válida.
  • c. [Char]. Esta alternativa não corresponde ao pedido. O resultado é uma lista numérica; [Int] é uma especialização válida.
  • d. [String]. Esta alternativa não corresponde ao pedido. O resultado é uma lista numérica; [Int] é uma especialização válida.
Voltar à explicação
Remover a cabeça de uma lista invertidaEscolha múltipla

Qual o resultado de executar o seguinte código?

tail (reverse [1,2,3])
A tua resposta

Solução
reverse produz [3,2,1], e tail remove o primeiro elemento.
  • a. [2,3]. Esta alternativa não corresponde ao pedido. reverse produz [3,2,1], e tail remove o primeiro elemento.
  • b. [2,1]. reverse produz [3,2,1], e tail remove o primeiro elemento.
  • c. [1,2]. Esta alternativa não corresponde ao pedido. reverse produz [3,2,1], e tail remove o primeiro elemento.
  • d. 1. Esta alternativa não corresponde ao pedido. reverse produz [3,2,1], e tail remove o primeiro elemento.
Voltar à explicação
Filtrar pares pelo produtoEscolha múltipla

Qual o resultado de executar o seguinte código?

[(x,y) | (x,y) <- [(1,2),(2,3)], x*y==6]
A tua resposta

Solução
Só o par (2,3) satisfaz o predicado, e o resultado é uma lista.
  • a. [(2,3)]. Só o par (2,3) satisfaz o predicado, e o resultado é uma lista.
  • b. [2,3]. Esta alternativa não corresponde ao pedido. Só o par (2,3) satisfaz o predicado, e o resultado é uma lista.
  • c. [(3,3)]. Esta alternativa não corresponde ao pedido. Só o par (2,3) satisfaz o predicado, e o resultado é uma lista.
  • d. (2,3). Esta alternativa não corresponde ao pedido. Só o par (2,3) satisfaz o predicado, e o resultado é uma lista.
Voltar à explicação
Repetir uma lista infinitaEscolha múltipla

Qual o resultado de executar o seguinte código?

cycle (cycle [1,2,3])
Nota: cycle é uma função do Prelúdio-padrão que produz uma lista infinita em que a lista de input é repetida um número infinito de vezes. Exemplo: cycle [1,2,3] = [1,2,3,1,2,3, …]
A tua resposta

Solução
A lista interior é infinita, por isso a repetição exterior nunca chega ao seu fim.
  • a. [1,1,1,1,1,1 …]. Esta alternativa não corresponde ao pedido. A lista interior é infinita, por isso a repetição exterior nunca chega ao seu fim.
  • b. O cálculo da expressão gera um erro.. Esta alternativa não corresponde ao pedido. A lista interior é infinita, por isso a repetição exterior nunca chega ao seu fim.
  • c. [1,2,3,1,2,3, …]. A lista interior é infinita, por isso a repetição exterior nunca chega ao seu fim.
  • d. [1,1,2,2,3,3,1,1,2,2,3,3, …]. Esta alternativa não corresponde ao pedido. A lista interior é infinita, por isso a repetição exterior nunca chega ao seu fim.
Voltar à explicação
Emparelhar elementos consecutivosEscolha múltipla

Qual o resultado de executar o seguinte código?

head (zip [1..10] (tail [1..10]))
A tua resposta

Solução
zip emparelha os primeiros elementos, 1 e 2.
  • a. (1,10). Esta alternativa não corresponde ao pedido. zip emparelha os primeiros elementos, 1 e 2.
  • b. (1,1). Esta alternativa não corresponde ao pedido. zip emparelha os primeiros elementos, 1 e 2.
  • c. (2,1). Esta alternativa não corresponde ao pedido. zip emparelha os primeiros elementos, 1 e 2.
  • d. (1,2). zip emparelha os primeiros elementos, 1 e 2.
Voltar à explicação
Árvores com valores nos nósEscolha múltipla
Qual das seguintes alternativas define um tipo de árvores binárias com anotações apenas nos nós?
A tua resposta

Solução
Folha não tem anotação; No tem um valor e duas subárvores.
  • a. data Arv a = Folha | No a (Arv a) (Arv a). Folha não tem anotação; No tem um valor e duas subárvores.
  • b. data Arv a = Folha a | No a (Arv a) (Arv a). Esta alternativa não corresponde ao pedido. Folha não tem anotação; No tem um valor e duas subárvores.
  • c. data Arv a = Folha a | No (Arv a) (Arv a). Esta alternativa não corresponde ao pedido. Folha não tem anotação; No tem um valor e duas subárvores.
  • d. data Arv = Folha | No Arv Arv. Esta alternativa não corresponde ao pedido. Folha não tem anotação; No tem um valor e duas subárvores.
Voltar à explicação
Remover um carácter de uma stringEscolha múltipla

Qual o resultado de executar o seguinte código?

filter (/='a') "abba"
A tua resposta

Solução
O predicado conserva os caracteres diferentes de a.
  • a. "ab". Esta alternativa não corresponde ao pedido. O predicado conserva os caracteres diferentes de a.
  • b. "". Esta alternativa não corresponde ao pedido. O predicado conserva os caracteres diferentes de a.
  • c. "bb". O predicado conserva os caracteres diferentes de a.
  • d. "aa". Esta alternativa não corresponde ao pedido. O predicado conserva os caracteres diferentes de a.
Voltar à explicação

Listas, avaliação e efeitos

Tipo de um par ordenadoEscolha múltipla

Qual é o tipo da função seguinte?

orderedPair (a, b)
   | a <= b = (a, b)
   | otherwise = (b, a)
A tua resposta

Solução
A comparação exige Ord e ambos os elementos têm o mesmo tipo.
  • a. (Num a, Num b) => (a, b) -> (b, a). Esta alternativa não corresponde ao pedido. A comparação exige Ord e ambos os elementos têm o mesmo tipo.
  • b. (Ord a) => (a, a) -> (a, a). A comparação exige Ord e ambos os elementos têm o mesmo tipo.
  • c. (Num a, Num b) => (a, b) -> (a, b). Esta alternativa não corresponde ao pedido. A comparação exige Ord e ambos os elementos têm o mesmo tipo.
  • d. (Ord a, Ord b) => (a, b) -> (b, a). Esta alternativa não corresponde ao pedido. A comparação exige Ord e ambos os elementos têm o mesmo tipo.
  • e. (Num a, Ord a, Num b, Ord b) => (a, b) -> (b, a). Esta alternativa não corresponde ao pedido. A comparação exige Ord e ambos os elementos têm o mesmo tipo.
Voltar à explicação
Contar valores positivos por composiçãoEscolha múltipla

Qual é o resultado da expressão?

(length . (filter (> 0))) [1, 2, -3, 4, -5]
A tua resposta

Solução
filter conserva 1, 2 e 4; length conta três.
  • a. 0. Esta alternativa não corresponde ao pedido. filter conserva 1, 2 e 4; length conta três.
  • b. The evaluation of the expression produces an error.. Esta alternativa não corresponde ao pedido. filter conserva 1, 2 e 4; length conta três.
  • c. 3. filter conserva 1, 2 e 4; length conta três.
  • d. 1. Esta alternativa não corresponde ao pedido. filter conserva 1, 2 e 4; length conta três.
  • e. 2. Esta alternativa não corresponde ao pedido. filter conserva 1, 2 e 4; length conta três.
Voltar à explicação
Lista de funções sobre listasEscolha múltipla

Qual é o tipo da expressão?

[(++) [], map (+1)]
A tua resposta

Solução
Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
  • a. [[a] -> [a]]. Esta alternativa não corresponde ao pedido. Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
  • b. (Num a) => [a]. Esta alternativa não corresponde ao pedido. Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
  • c. (Num a, Num b) => [[a] -> [b]]. Esta alternativa não corresponde ao pedido. Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
  • d. [[a] -> [b]]. Esta alternativa não corresponde ao pedido. Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
  • e. (Num a) => [[a] -> [a]]. Ambas as funções transformam listas do mesmo tipo numérico, pelo uso de (+1).
Voltar à explicação
Tipo de uma função sobre triplosEscolha múltipla

Qual é o tipo da função?

fun (x, y, _) = (y, x, y)
fun (_, y, x) = (y, x, y)
A tua resposta

Solução
A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
  • a. (a, a, a) -> (a, a, a). Esta alternativa não corresponde ao pedido. A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
  • b. (a, b, c) -> (a, b, c). Esta alternativa não corresponde ao pedido. A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
  • c. (a, b, a) -> (b, a, b). A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
  • d. (a, b, c) -> (d, e, f). Esta alternativa não corresponde ao pedido. A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
  • e. (a, a, a) -> (b, b, b). Esta alternativa não corresponde ao pedido. A segunda equação é inacessível, mas também é verificada: a primeira e a terceira posições têm de ter o mesmo tipo.
Voltar à explicação
Combinar letras e númerosEscolha múltipla

Qual é o resultado da expressão?

[(a, b) | a <- "abc", b <- [1, 2], a <= 'd']
A tua resposta

Solução
A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
  • a. [('a',1), ('b',1), ('c',1), ('a',2), ('b',2), ('c',2)]. Esta alternativa não corresponde ao pedido. A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
  • b. [('a',1), ('a',2), ('b',1), ('b',2), ('c',1), ('c',2)]. A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
  • c. The evaluation of the expression produces an error.. Esta alternativa não corresponde ao pedido. A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
  • d. [('a',1), ('b',1), ('c',1)]. Esta alternativa não corresponde ao pedido. A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
  • e. []. Esta alternativa não corresponde ao pedido. A condição é verdadeira para as três letras e o segundo gerador varia primeiro.
Voltar à explicação
Dividir com foldlEscolha múltipla

Qual é o resultado da expressão?

foldl (/) 200 [1, 2, 4]
A tua resposta

Solução
A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
  • a. 50.0. Esta alternativa não corresponde ao pedido. A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
  • b. The evaluation of the expression produces an error.. Esta alternativa não corresponde ao pedido. A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
  • c. 25.0. A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
  • d. 100.0. Esta alternativa não corresponde ao pedido. A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
  • e. 1.0e-2. Esta alternativa não corresponde ao pedido. A associação à esquerda dá ((200 / 1) / 2) / 4 = 25.0.
Voltar à explicação
Resultados das funções do PreludeEscolha múltipla

Qual das funções do Prelude não devolve necessariamente uma lista?

A tua resposta

Solução
(!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
  • a. (++). Esta alternativa não corresponde ao pedido. (!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
  • b. (:). Esta alternativa não corresponde ao pedido. (!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
  • c. zip. Esta alternativa não corresponde ao pedido. (!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
  • d. init. Esta alternativa não corresponde ao pedido. (!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
  • e. (!!). (!!) seleciona um elemento, cujo tipo não tem de ser uma lista.
Voltar à explicação
Variáveis de tipo, recursão e instânciasEscolha múltipla

Considera as seguintes afirmações sobre type e data. Quais estão corretas?

A - type does not allow the use of type variables, unlike data. B - type does not allow recursive type definitions. C - It is possible to define an instance of Eq using data.
A tua resposta

Solução
type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
  • a. Only B and C.. type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
  • b. Only A and B.. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
  • c. Only A and C.. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
  • d. Only B.. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
  • e. A, B and C.. Esta alternativa não corresponde ao pedido. type aceita variáveis, mas não sinónimos recursivos. data permite definir uma instância de Eq.
Voltar à explicação
Reconhecer mónadasEscolha múltipla

Entre Maybe, State e IO, quais são mónadas?

A tua resposta

Solução
Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
  • a. Maybe, State and IO.. Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
  • b. Only Maybe and IO.. Esta alternativa não corresponde ao pedido. Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
  • c. Only State and IO.. Esta alternativa não corresponde ao pedido. Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
  • d. Only IO.. Esta alternativa não corresponde ao pedido. Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
  • e. None of these types is a monad.. Esta alternativa não corresponde ao pedido. Maybe, IO e State são mónadas, com o parâmetro de estado de State fixado.
Voltar à explicação
Tipo de uma saudação com IOEscolha múltipla

Qual é o tipo da função seguinte?

howdy name = putStrLn ("howdy " ++ name ++ "!")
A tua resposta

Solução
putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
  • a. String -> IO (). putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
  • b. String -> String. Esta alternativa não corresponde ao pedido. putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
  • c. IO (). Esta alternativa não corresponde ao pedido. putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
  • d. IO (String). Esta alternativa não corresponde ao pedido. putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
  • e. String -> IO (String). Esta alternativa não corresponde ao pedido. putStrLn devolve uma ação IO (), pelo que a função recebe String e devolve IO ().
Voltar à explicação
Avaliação preguiçosa e listas infinitasEscolha múltipla

A avaliação preguiçosa de Haskell permite o quê?

A tua resposta

Solução
A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
  • a. the automatic inference of the functions’ type.. Esta alternativa não corresponde ao pedido. A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
  • b. the optimization of the memory consumption of a program, in exchange for an increased execution time.. Esta alternativa não corresponde ao pedido. A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
  • c. the definition of polymorphic functions.. Esta alternativa não corresponde ao pedido. A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
  • d. certain computations with infinite data structures to be finite.. A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
  • e. the definition of higher-order functions.. Esta alternativa não corresponde ao pedido. A avaliação preguiçosa permite obter resultados finitos sem avaliar uma estrutura infinita inteira.
Voltar à explicação
Representar um dendrogramaEscolha múltipla

Um dendrograma é uma árvore binária cujos caminhos chegam a strings. Cada nó não folha indica a distância horizontal igual aos dois filhos. Qual é a definição mais adequada?

5533dogcatoctopus
Cada nó interno guarda uma distância comum aos seus dois filhos.
A tua resposta

Solução
Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
  • a. data Dendrogram = Leaf String | Node Int Int Dendrogram. Esta alternativa não corresponde ao pedido. Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
  • b. (Integral a) => data Dendrogram = Leaf (String, a) | Node Dendrogram Dendrogram. Esta alternativa não corresponde ao pedido. Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
  • c. data Dendrogram = Leaf (String, Int) | Node Dendrogram Dendrogram. Esta alternativa não corresponde ao pedido. Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
  • d. (Integral a) => data Dendrogram = Leaf String | Node Dendrogram a a Dendrogram. Esta alternativa não corresponde ao pedido. Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
  • e. data Dendrogram = Leaf String | Node Dendrogram Int Dendrogram. Cada folha guarda uma String e cada nó guarda duas subárvores e uma distância comum.
Voltar à explicação

Composição e avaliação

Custo da concatenação de listasEscolha múltipla

Ordena por tempo de avaliação, começando pela mais rápida. Para tornar a comparação determinada, considera apenas o custo de percorrer o argumento esquerdo de (++) para produzir a lista inteira, sem contar a construção das listas.

a = [1 .. 100000] ++ (take 1000 [1 .. 100000])
b = (take 1000 [1 .. 100000]) ++ [1 .. 100000]
c = (takeWhile (>1000) [1 .. 100000]) ++ [1 .. 100000]
A tua resposta

Solução
O argumento esquerdo de (++) tem zero elementos em c, 1000 em b e 100000 em a. No modelo indicado, a ordem é c < b < a.
  • a. a = b = c. No modelo pedido, (++) percorre a lista à esquerda: c começa com [], b com 1000 elementos e a com 100000. O tempo real depende do contexto de avaliação.
  • b. b < c < a. No modelo pedido, (++) percorre a lista à esquerda: c começa com [], b com 1000 elementos e a com 100000. O tempo real depende do contexto de avaliação.
  • c. c < a = b. No modelo pedido, (++) percorre a lista à esquerda: c começa com [], b com 1000 elementos e a com 100000. O tempo real depende do contexto de avaliação.
  • d. c < b < a. No modelo pedido, (++) percorre a lista à esquerda: c começa com [], b com 1000 elementos e a com 100000. O tempo real depende do contexto de avaliação.
  • e. c < a < b. No modelo pedido, (++) percorre a lista à esquerda: c começa com [], b com 1000 elementos e a com 100000. O tempo real depende do contexto de avaliação.
Voltar à explicação
Intercalar caracteres com zip e concatEscolha múltipla

Qual é o resultado?

concat [[a,b] | (a,b) <- zip ['a' ..] "abcde"]
A tua resposta

Solução
zip termina com a segunda lista; concat junta os pares de caracteres numa string.
  • a. ["abcde,"abcde,"abcde","abcde","abcde"]. Esta alternativa não corresponde ao pedido. zip termina com a segunda lista; concat junta os pares de caracteres numa string.
  • b. ["aa","bb","cc","dd","ee"]. Esta alternativa não corresponde ao pedido. zip termina com a segunda lista; concat junta os pares de caracteres numa string.
  • c. [('a','a'),('b','b'),('c','c'),('d','d'),('e','e')]. Esta alternativa não corresponde ao pedido. zip termina com a segunda lista; concat junta os pares de caracteres numa string.
  • d. "abcdeabcde". Esta alternativa não corresponde ao pedido. zip termina com a segunda lista; concat junta os pares de caracteres numa string.
  • e. "aabbccddee". zip termina com a segunda lista; concat junta os pares de caracteres numa string.
Voltar à explicação
Multiplicar sequências com zipWithEscolha múltipla

Qual é o resultado?

zipWith (*) [1 ..] [3,1 .. -5]
A tua resposta

Solução
A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
  • a. [3,2,-3,-12,-25]. A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
  • b. Nenhuma das outras opções.. Esta alternativa não corresponde ao pedido. A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
  • c. []. Esta alternativa não corresponde ao pedido. A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
  • d. Uma lista infinita. Esta alternativa não corresponde ao pedido. A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
  • e. [-3,-2,3,12,25]. Esta alternativa não corresponde ao pedido. A segunda lista é [3,1,-1,-3,-5], e zipWith termina no seu fim.
Voltar à explicação
Reconhecer uma propriedade sobre listasEscolha múltipla

Que expressão tem o tipo (Eq a) => [a] -> Bool?

A tua resposta

Solução
Comparar a lista com a sua inversa exige Eq e produz Bool.
  • a. (\(_:t) -> tail t). Esta alternativa não corresponde ao pedido. Comparar a lista com a sua inversa exige Eq e produz Bool.
  • b. map (<3). Esta alternativa não corresponde ao pedido. Comparar a lista com a sua inversa exige Eq e produz Bool.
  • c. filter (==3). Esta alternativa não corresponde ao pedido. Comparar a lista com a sua inversa exige Eq e produz Bool.
  • d. tail. Esta alternativa não corresponde ao pedido. Comparar a lista com a sua inversa exige Eq e produz Bool.
  • e. (\l -> reverse l == l). Comparar a lista com a sua inversa exige Eq e produz Bool.
Voltar à explicação
Tipo de uma comparação de quocientesEscolha múltipla

Qual é o tipo de myFun?

myFun x y = (x / y) < 1
A tua resposta

Solução
O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
  • a. (Num a, Ord a) => a -> a -> Bool. Esta alternativa não corresponde ao pedido. O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
  • b. Nenhuma das outras opções.. O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
  • c. (Floating a) => a -> a -> Bool. Esta alternativa não corresponde ao pedido. O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
  • d. (Floating a, Ord a) => a -> b -> Bool. Esta alternativa não corresponde ao pedido. O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
  • e. (Fractional a, Ord a) => a -> b -> Bool. Esta alternativa não corresponde ao pedido. O tipo principal é (Fractional a, Ord a) => a -> a -> Bool, que não figura nas opções.
Voltar à explicação
Produto de positivos com MaybeEscolha múltipla

Qual das afirmações é falsa? A opção a contém o lapso Integral em vez do tipo Integer; para responder, aplica a errata indicada.

f [] = Just 1
f (h:t)
  | h > 0 = case f t of Just d -> Just (h*d)
                        _ -> Nothing
  | otherwise = Nothing
A tua resposta

Solução
A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
  • a. Os elementos podem ter tipo Int, Integral e Float, entre outros tipos válidos. [Errata: lê Integer no lugar de Integral.]. Esta alternativa não corresponde ao pedido. A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
  • b. Se uma entrada devolver Nothing, a sua inversa também devolve Nothing.. Esta alternativa não corresponde ao pedido. A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
  • c. O tipo é (Num a, Ord a) => [a] -> Maybe a.. Esta alternativa não corresponde ao pedido. A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
  • d. f [0 ..] termina e devolve Just 0.. A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
  • e. f [1,2,3,4] devolve Just 24.. Esta alternativa não corresponde ao pedido. A primeira guarda falha para 0 e o resultado imediato é Nothing. Integral é uma classe, não um tipo concreto.
Voltar à explicação
Reconhecer uma função definida com foldrEscolha múltipla

Qual a função do Prelude equivalente?

mysteryFunc = foldr (++) []
A tua resposta

Solução
foldr (++) [] concatena as listas pela ordem original.
  • a. reverse. Esta alternativa não corresponde ao pedido. foldr (++) [] concatena as listas pela ordem original.
  • b. (:). Esta alternativa não corresponde ao pedido. foldr (++) [] concatena as listas pela ordem original.
  • c. concat. foldr (++) [] concatena as listas pela ordem original.
  • d. length. Esta alternativa não corresponde ao pedido. foldr (++) [] concatena as listas pela ordem original.
  • e. tail. Esta alternativa não corresponde ao pedido. foldr (++) [] concatena as listas pela ordem original.
Voltar à explicação
Tipo de uma função de ordem superiorEscolha múltipla

Qual é o tipo da função?

fun f g x y = f (g x y) (f x x)
A tua resposta

Solução
f x x força f a receber e devolver a; g recebe a e b e devolve a.
  • a. (a -> a -> b) -> (a -> a -> a) -> a -> b -> a. Esta alternativa não corresponde ao pedido. f x x força f a receber e devolver a; g recebe a e b e devolve a.
  • b. (a -> a -> c) -> (a -> b -> a) -> a -> b -> c. Esta alternativa não corresponde ao pedido. f x x força f a receber e devolver a; g recebe a e b e devolve a.
  • c. (a -> a -> a) -> (a -> b -> a) -> a -> b -> a. f x x força f a receber e devolver a; g recebe a e b e devolve a.
  • d. Nenhuma das outras opções.. Esta alternativa não corresponde ao pedido. f x x força f a receber e devolver a; g recebe a e b e devolve a.
  • e. (a -> a -> b) -> (a -> b -> a) -> a -> b -> b. Esta alternativa não corresponde ao pedido. f x x força f a receber e devolver a; g recebe a e b e devolve a.
Voltar à explicação
Compor transformações antes de foldlEscolha múltipla

Qual é o resultado?

foldl (-) 2 (map ((+1).(*2)) [3,2,1])
A tua resposta

Solução
map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
  • a. -13. map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
  • b. 4. Esta alternativa não corresponde ao pedido. map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
  • c. Nenhuma das outras opções.. Esta alternativa não corresponde ao pedido. map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
  • d. 3. Esta alternativa não corresponde ao pedido. map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
  • e. -16. Esta alternativa não corresponde ao pedido. map produz [7,5,3]; a redução é ((2-7)-5)-3 = -13.
Voltar à explicação
Leitura recursiva de caracteresEscolha múltipla

O que faz g? As cinco opções originais descrevem impressão, mas o código só devolve um valor. A opção f foi acrescentada para permitir uma resposta tecnicamente correta.

g = gAux []

gAux a = do
  x <- getChar
  if (x == '\n')
    then return a
    else gAux (x:a)
A tua resposta

Solução
O código lê até à mudança de linha e devolve a linha invertida em IO String. Não contém uma ação de impressão.
  • a. Lê um carácter e imprime-o depois de lhe acrescentar uma mudança de linha.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
  • b. Lê várias linhas e imprime-as em ordem inversa.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
  • c. Lê uma linha e imprime-a exatamente como foi escrita.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
  • d. Lê uma linha e imprime-a em ordem inversa.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
  • e. Lê várias linhas e imprime-as exatamente como foram escritas.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
  • f. Lê uma linha e devolve-a invertida, sem a imprimir.. getChar lê até à mudança de linha; (x:a) acumula em ordem inversa e return devolve a string em IO. Não há putStr nem putStrLn.
Voltar à explicação

Ligas, percursos e árvores

Não uses funções de biblioteca nem importes módulos, salvo indicação explícita. Podes usar as funções fornecidas no código inicial. Os testes verificam o resultado, não o método.

Determinar o vencedor de uma partidaCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Implement winner :: Match -> String, which, given a match, returns the name of the match's winner or "draw" in case both teams scored the same number of goals.

Examples:

ghci> winner (("Porto","Benfica"),(5,0))
"Porto"
ghci> winner (("Porto","Sporting"),(2,2))
"draw"
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
winner :: Match -> String
winner = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Casa
    Código do teste
    main = print (winner (("Porto","Benfica"),(5,0)))
    Esperado:
    "Porto"
  2. Empate
    Código do teste
    main = print (winner (("Porto","Sporting"),(2,2)))
    Esperado:
    "draw"
  3. Fora
    Código do teste
    main = print (winner (("A","B"),(0,3)))
    Esperado:
    "B"

Solução
winner ((h,a),(x,y)) | x > y = h | x < y = a | otherwise = "draw"

Compara os golos das duas equipas; a igualdade é empate.

Voltar à explicação
Pontuação de uma equipa numa jornadaCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Implement matchDayScore :: String -> MatchDay -> Int, which, given a team and a matchday, returns the score obtained by that team on their match of that matchday. Winning a match gives a team 3 points, drawing gives 1 point and losing gives 0 points. If the input team does not exist in the league, then return 0.

Examples:

ghci> matchDayScore "Porto" (myLeague !! 0)
1
ghci> matchDayScore "Benfica" (myLeague !! 0)
3
ghci> matchDayScore "Vitoria SC" (myLeague !! 0)
0
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
matchDayScore :: String -> MatchDay -> Int
matchDayScore = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Empate
    Código do teste
    main = print (matchDayScore "Porto" (myLeague !! 0))
    Esperado:
    1
  2. Vitória
    Código do teste
    main = print (matchDayScore "Benfica" (myLeague !! 0))
    Esperado:
    3
  3. Derrota
    Código do teste
    main = print (matchDayScore "Vitoria SC" (myLeague !! 0))
    Esperado:
    0
  4. Ausente
    Código do teste
    main = print (matchDayScore "X" [])
    Esperado:
    0

Solução
matchDayScore _ [] = 0
matchDayScore t (((h,a),(x,y)):ms)
  | t == h = if x > y then 3 else if x == y then 1 else 0
  | t == a = if y > x then 3 else if x == y then 1 else 0
  | otherwise = matchDayScore t ms

Procura o jogo da equipa e compara os golos na orientação correta.

Voltar à explicação
Classificação de uma ligaCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Podes usar leagueScore, sortByCond e merge, fornecidas no código inicial.

Implement ranking:: League -> [(String,Int)], which returns a list of pairs (team,score) with the score obtained by each team during the league. The league score is the sum of the points obtained by the team in each matchday. The output list must be ordered by the scores, in decreasing order. In case of a tie in the scores, return the team name that comes first alphabetically.

Examples:

ghci> ranking myLeague
[("Porto",7),("Sporting",4),("Benfica",3),("Vitoria SC",3)]
ghci> ranking (tail myLeague)
[("Porto",6),("Sporting",3),("Vitoria SC",3),("Benfica",0)]
ghci> ranking []
[]
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
matchDayScore :: String -> MatchDay -> Int
matchDayScore _ [] = 0
matchDayScore t (((h,a),(x,y)):ms)
  | t == h = if x > y then 3 else if x == y then 1 else 0
  | t == a = if y > x then 3 else if x == y then 1 else 0
  | otherwise = matchDayScore t ms
leagueScore :: String -> League -> Int
leagueScore t = foldr (\d acc -> matchDayScore t d + acc) 0
sortByCond :: Ord a => [a] -> (a -> a -> Bool) -> [a]
sortByCond [] _ = []
sortByCond [x] _ = [x]
sortByCond l cmp = merge (sortByCond l1 cmp) (sortByCond l2 cmp) cmp
  where (l1,l2) = splitAt (div (length l) 2) l
merge :: Ord a => [a] -> [a] -> (a -> a -> Bool) -> [a]
merge [] l _ = l
merge l [] _ = l
merge (x:xs) (y:ys) cmp
  | cmp x y = x : merge xs (y:ys) cmp
  | otherwise = y : merge (x:xs) ys cmp
ranking :: League -> [(String,Int)]
ranking = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Liga
    Código do teste
    main = print (ranking myLeague)
    Esperado:
    [("Porto",7),("Sporting",4),("Benfica",3),("Vitoria SC",3)]
  2. Cauda
    Código do teste
    main = print (ranking (tail myLeague))
    Esperado:
    [("Porto",6),("Sporting",3),("Vitoria SC",3),("Benfica",0)]
  3. Vazia
    Código do teste
    main = print (ranking [])
    Esperado:
    []

Solução
unique [] = []
unique (x:xs) = x : unique [y | y <- xs, y /= x]
ranking l = sortByCond [(t,leagueScore t l) | t <- unique [t | d <- l, ((h,a),_) <- d, t <- [h,a]]] cmp
  where cmp (a,x) (b,y) = x > y || (x == y && a < b)

Recolhe cada equipa uma vez e ordena por pontos decrescentes, usando o nome para desempatar.

Voltar à explicação
Contar jornadas com empatesCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Implement numMatchDaysWithDraws :: League -> Int, which returns the amount of matchdays in the league where at least one match ended in a draw. Constraint: in this exercise, you must use higher-order functions. You are not allowed to define new recursive functions or use list comprehensions.

Examples:

ghci> numMatchDaysWithDraws myLeague
1
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
winner :: Match -> String
winner ((h,a),(x,y)) | x > y = h | x < y = a | otherwise = "draw"
numMatchDaysWithDraws :: League -> Int
numMatchDaysWithDraws = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Liga
    Código do teste
    main = print (numMatchDaysWithDraws myLeague)
    Esperado:
    1
  2. Vazia
    Código do teste
    main = print (numMatchDaysWithDraws [])
    Esperado:
    0
  3. Dois empates
    Código do teste
    main = print (numMatchDaysWithDraws [[(("A","B"),(0,0)),(("C","D"),(1,1))]])
    Esperado:
    1

Solução
numMatchDaysWithDraws = length . filter (any ((== "draw") . winner))

Conta cada jornada que contém pelo menos um empate.

Voltar à explicação
Identificar vitórias por goleadaCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Implement bigWins :: League -> [(Int,[String])], which returns a list of pairs (i,ws), where i is the index of the matchday (with indices starting at 1) and ws are the names of teams from that matchday that won their match with a goal difference of at least 3 goals. Any order of the winners ws of each matchday will be accepted. Constraint: in this exercise, you must use list comprehensions. You are not allowed to define new recursive functions or use higher-order functions (map, filter, foldl ...).

Examples:

ghci> bigWins myLeague
[(1,["Benfica"]),(2,["Porto"]),(3,[])]
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
winner :: Match -> String
winner ((h,a),(x,y)) | x > y = h | x < y = a | otherwise = "draw"
bigWins :: League -> [(Int,[String])]
bigWins = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Liga
    Código do teste
    main = print (bigWins myLeague)
    Esperado:
    [(1,["Benfica"]),(2,["Porto"]),(3,[])]
  2. Vazia
    Código do teste
    main = print (bigWins [])
    Esperado:
    []
  3. Limite
    Código do teste
    main = print (bigWins [[(("A","B"),(0,3))]])
    Esperado:
    [(1,["B"])]

Solução
bigWins l = [(i,[winner m | m@(_, (x,y)) <- d, abs (x-y) >= 3]) | (i,d) <- zip [1..] l]

A compreensão exterior conserva todas as jornadas; a interior seleciona diferenças de pelo menos três golos.

Voltar à explicação
Encontrar séries de vitóriasCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma liga é uma sequência de jornadas. Cada equipa joga uma partida por jornada; cada partida contém as equipas da casa e visitante e os respetivos golos. Por exemplo, (("Porto","Benfica"),(5,0)) representa uma vitória do Porto por 5–0. As definições e os exemplos da liga estão no código inicial.

Implement winningStreaks :: League -> [(String,Int,Int)], which returns a list of winning streaks, described by a triple (t,s,e), where: t is the name of the team involved in the winning streak; s and e are the indices of the streak's first and last matchday (with indices starting at 1). A winning streak is a sequence of wins in 2 or more consecutive matchdays. Note that the same team may have more than one winning streak and thus appear multiple times in the output. Any order of the output list will be accepted.

Examples:

ghci> winningStreaks myLeague
[("Porto",2,3)]
ghci> winningStreaks [[(("RM","Barca"),(4,0))],[(("Barca","RM"),(1,2))],[(("RM","Barca"),(2,2))],[(("RM","Barca"),
(0,4))],[(("Barca","RM"),(3,0))],[(("Barca","RM"),(3,1))]]
[("RM",1,2),("Barca",4,6)]
Haskell
type Match = ((String,String), (Int,Int))
type MatchDay = [Match]
type League = [MatchDay]
myLeague :: League
myLeague = [[(("Porto","Sporting"),(2,2)),(("Benfica","Vitoria SC"),(4,0))],
  [(("Porto","Benfica"),(5,0)),(("Vitoria SC","Sporting"),(3,2))],
  [(("Vitoria SC","Porto"),(1,2)),(("Sporting","Benfica"),(2,1))]]
winner :: Match -> String
winner ((h,a),(x,y)) | x > y = h | x < y = a | otherwise = "draw"
winningStreaks :: League -> [(String,Int,Int)]
winningStreaks = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Liga
    Código do teste
    main = print (winningStreaks myLeague)
    Esperado:
    [("Porto",2,3)]
  2. Vazia
    Código do teste
    main = print (winningStreaks [])
    Esperado:
    []
  3. Duas equipas
    Código do teste
    main = print (let r = winningStreaks [[(("RM","Barca"),(4,0))],[(("Barca","RM"),(1,2))],[(("RM","Barca"),(2,2))],[(("RM","Barca"),(0,4))],[(("Barca","RM"),(3,0))],[(("Barca","RM"),(3,1))]] in (elem ("RM",1,2) r, elem ("Barca",4,6) r, length r))
    Esperado:
    (True,True,2)

Solução
unique [] = []
unique (x:xs) = x : unique [y | y <- xs, y /= x]
runs t [] = []
runs t (i:is) = extend t i i is
extend t s e (i:is) | i == e+1 = extend t s i is
extend t s e rest = (if e > s then [(t,s,e)] else []) ++ runs t rest
winningStreaks l = concat [runs t [i | (i,d) <- zip [1..] l, m <- d, winner m == t] | t <- unique [t | d <- l, ((h,a),_) <- d, t <- [h,a]]]

Agrupa, para cada equipa, índices consecutivos de vitórias e descarta grupos de uma só jornada.

Voltar à explicação
Cidades adjacentes e distânciasCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

RoadMap representa estradas não orientadas entre cidades, com as respetivas distâncias. Os mapas de exemplo estão no código inicial; gTest2 é desconexo.

Implement adjacent :: RoadMap -> City ->[(City,Distance)], which returns the cities adjacent to a particular city (i.e. cities with a direct edge between them) and the respective distances to them. Any order of the output list will be accepted. Note that a city is NOT adjacent to itself.

Examples:

ghci> adjacent gTest1 "0"
[("1",10),("2",15),("3",20)]
ghci> adjacent gTest2 "0"
[("1",4)]
Haskell
type City = String
type Path = [City]
type Distance = Int
type RoadMap = [(City,City,Distance)]
gTest1 :: RoadMap
gTest1 = [("0","1",10),("0","2",15),("0","3",20),("1","2",35),("1","3",25),("2","3",30)]
gTest2 :: RoadMap
gTest2 = [("0","1",4),("2","3",2)]
adjacent :: RoadMap -> City -> [(City,Distance)]
adjacent = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Mapa
    Código do teste
    main = print (let r = adjacent gTest1 "0" in (length r, elem ("1",10) r, elem ("2",15) r, elem ("3",20) r))
    Esperado:
    (3,True,True,True)
  2. Desconexo
    Código do teste
    main = print (adjacent gTest2 "0")
    Esperado:
    [("1",4)]
  3. Laço
    Código do teste
    main = print (adjacent [("A","A",1)] "A")
    Esperado:
    []

Solução
adjacent rs c = [(b,d) | (a,b,d) <- rs, a == c, b /= c] ++ [(a,d) | (a,b,d) <- rs, b == c, a /= c]

Percorre as estradas nos dois sentidos e exclui laços.

Voltar à explicação
Verificar ligações entre cidadesCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

RoadMap representa estradas não orientadas entre cidades, com as respetivas distâncias. Os mapas de exemplo estão no código inicial; gTest2 é desconexo.

Implement areConnected :: RoadMap -> City -> City -> Bool, which determines if there is a path, composed of one or more roads, connecting both input cities of the input roadmap. Consider that a city is connected to itself.

Examples:

ghci> areConnected gTest1 "0" "3"
True
ghci> areConnected gTest2 "0" "3"
False
Haskell
type City = String
type Path = [City]
type Distance = Int
type RoadMap = [(City,City,Distance)]
gTest1 :: RoadMap
gTest1 = [("0","1",10),("0","2",15),("0","3",20),("1","2",35),("1","3",25),("2","3",30)]
gTest2 :: RoadMap
gTest2 = [("0","1",4),("2","3",2)]
adjacent :: RoadMap -> City -> [(City,Distance)]
adjacent rs c = [(b,d) | (a,b,d) <- rs, a == c, b /= c] ++ [(a,d) | (a,b,d) <- rs, b == c, a /= c]
areConnected :: RoadMap -> City -> City -> Bool
areConnected = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ligadas
    Código do teste
    main = print (areConnected gTest1 "0" "3")
    Esperado:
    True
  2. Desligadas
    Código do teste
    main = print (areConnected gTest2 "0" "3")
    Esperado:
    False
  3. Mesma
    Código do teste
    main = print (areConnected [] "X" "X")
    Esperado:
    True
  4. Ciclo
    Código do teste
    main = print (areConnected [("A","B",1),("B","C",1),("C","A",1)] "A" "Z")
    Esperado:
    False

Solução
areConnected roads start end = search [] [start]
  where
    search _ [] = False
    search seen (c:cs)
      | c == end = True
      | c `elem` seen = search seen cs
      | otherwise = search (c:seen) (map fst (adjacent roads c) ++ cs)

A pesquisa guarda cidades visitadas para terminar mesmo com ciclos. A cidade inicial está ligada a si própria.

Voltar à explicação
Inserir um ponto numa KD-treeCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma KD-tree guarda pontos distintos. A raiz não vazia é um nó X e os níveis alternam entre X e Y. À esquerda ficam pontos com coordenada do eixo estritamente inferior; à direita, igual ou superior. Pontos distintos podem partilhar uma coordenada. As árvores de exemplo estão no código inicial.

Implement insert :: (Int,Int) -> KdTree -> KdTree, which given a point p and a tree t, returns a new tree with the result of adding p to t. Point p should be added on the appropriate leaf node (Empty), according to the rules of the kd-tree stated before. If point p is already in the tree, then return t.

Examples:

ghci> insert (3,2) tree1
Node 'x' (3,3) (Node 'y' (2,2) Empty Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)
ghci> insert (1,1) (insert (3,2) tree1)
Node 'x' (3,3) (Node 'y' (2,2) (Node 'x' (1,1) Empty Empty) Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)
Haskell
data KdTree = Empty | Node Char (Int,Int) KdTree KdTree deriving (Eq,Show)
tree1 :: KdTree
tree1 = Node 'x' (3,3) (Node 'y' (2,2) Empty Empty) (Node 'y' (4,4) Empty Empty)
tree2 :: KdTree
tree2 = Node 'x' (3,3) (Node 'y' (2,2) (Node 'x' (1,1) Empty Empty) Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)
insert :: (Int,Int) -> KdTree -> KdTree
insert = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Raiz
    Código do teste
    main = print (insert (1,2) Empty)
    Esperado:
    Node 'x' (1,2) Empty Empty
  2. Exemplo
    Código do teste
    main = print (insert (3,2) tree1)
    Esperado:
    Node 'x' (3,3) (Node 'y' (2,2) Empty Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)
  3. Duplicado
    Código do teste
    main = print (insert (3,2) tree2)
    Esperado:
    Node 'x' (3,3) (Node 'y' (2,2) (Node 'x' (1,1) Empty Empty) Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)

Solução
insert p = go 'x'
  where
    go axis Empty = Node axis p Empty Empty
    go _ node@(Node a q left right)
      | p == q = node
      | coordinate a p < coordinate a q = Node a q (go (next a) left) right
      | otherwise = Node a q left (go (next a) right)
    coordinate 'x' (x,_) = x
    coordinate _ (_,y) = y
    next 'x' = 'y'
    next _ = 'x'

Coordenadas iguais seguem para a direita; o eixo alterna ao descer. Um ponto igual já existe.

Voltar à explicação
Imprimir uma KD-tree com indentaçãoCódigo

You cannot use library functions or import modules, unless clearly stated otherwise.

Uma KD-tree guarda pontos distintos. A raiz não vazia é um nó X e os níveis alternam entre X e Y. À esquerda ficam pontos com coordenada do eixo estritamente inferior; à direita, igual ou superior. Pontos distintos podem partilhar uma coordenada. As árvores de exemplo estão no código inicial.

Implement putTreeStr :: KdTree -> IO (), which prints the contents of the tree in several lines, in a user-friendly manner. The output format must be exactly as detailed in the examples (including regarding the ' ' and newlines). Each tree is printed as follows: a line for the root's point; a line with the condition that all points of the left child must follow; the left child (if it exists); a line with the condition that all points of the right child must follow; the right child (if it exists). At each level of depth in tree, all of the prints must be prefixed by exactly two additional spaces: " ". Note that nothing should be printed for empty trees.

Examples:

ghci> putTreeStr Empty
ghci> putTreeStr tree1
(3,3)
x<3
  (2,2)
  y<2
  y>=2
x>=3
  (4,4)
  y<4
  y>=4
ghci> putTreeStr tree2
(3,3)
x<3
  (2,2)
  y<2
      (1,1)
      x<1
    x>=1
  y>=2
x>=3
  (4,4)
  y<4
      (3,2)
      x<3
    x>=3
  y>=4
Haskell
data KdTree = Empty | Node Char (Int,Int) KdTree KdTree deriving (Eq,Show)
tree1 :: KdTree
tree1 = Node 'x' (3,3) (Node 'y' (2,2) Empty Empty) (Node 'y' (4,4) Empty Empty)
tree2 :: KdTree
tree2 = Node 'x' (3,3) (Node 'y' (2,2) (Node 'x' (1,1) Empty Empty) Empty) (Node 'y' (4,4) (Node 'x' (3,2) Empty Empty) Empty)
putTreeStr :: KdTree -> IO ()
putTreeStr = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Vazia
    Código do teste
    main = print =<< (putTreeStr Empty)
    Esperado:
    ()
  2. Um nó
    Código do teste
    main = print =<< (putTreeStr (Node 'x' (1,2) Empty Empty))
    Esperado:
    (1,2)
    x<1
    x>=1
    ()
  3. Árvore
    Código do teste
    main = print =<< (putTreeStr tree1)
    Esperado:
    (3,3)
    x<3
      (2,2)
      y<2
      y>=2
    x>=3
      (4,4)
      y<4
      y>=4
    ()

Solução
putTreeStr = go ""
  where
    go _ Empty = return ()
    go indent (Node axis p@(x,y) left right) = do
      putStrLn (indent ++ show p)
      let value = if axis == 'x' then x else y
      putStrLn (indent ++ [axis] ++ "<" ++ show value)
      go (indent ++ "  ") left
      putStrLn (indent ++ [axis] ++ ">=" ++ show value)
      go (indent ++ "  ") right

Imprime as condições mesmo quando a subárvore é vazia e acrescenta dois espaços por nível.

Voltar à explicação

Catálogos, sequências e proposições

Procurar os atores de um filmeCódigo

Cada Movie é um par com o título e uma lista ordenada de atores. Podes usar delAll, que remove todas as ocorrências, e uniqueVals, que remove repetidos mantendo a primeira ocorrência. Implemente findActors :: [Movie] -> String -> Maybe [String]. Devolva os atores do filme com o título indicado, ou Nothing se não existir.

Haskell
type Movie = (String, [String])
myMovies :: [Movie]
myMovies = [("Titanic",["Kate Winslet","Leonardo DiCaprio"]),("Revolutionary Road",["Kate Winslet","Leonardo DiCaprio"]),("Elektra ",["Jennifer Garner"]),("The Great Gatsby",["Leonardo DiCaprio"])]
delAll :: Eq a => a -> [a] -> [a]
delAll x = filter (/= x)
uniqueVals :: Eq a => [a] -> [a]
uniqueVals [] = []
uniqueVals (x:xs) = x : uniqueVals (delAll x xs)
findActors :: [Movie] -> String -> Maybe [String]
findActors = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Existe
    Código do teste
    main = print (findActors [("A",["X","Y"])] "A")
    Esperado:
    Just ["X","Y"]
  2. Ausente
    Código do teste
    main = print (findActors [] "A")
    Esperado:
    Nothing

Solução
findActors movies title = lookup title movies

lookup title movies procura o primeiro par com esse título. A ausência é representada por Nothing.

Voltar à explicação
Selecionar filmes por atorCódigo

Cada Movie é um par com o título e uma lista ordenada de atores. Podes usar delAll, que remove todas as ocorrências, e uniqueVals, que remove repetidos mantendo a primeira ocorrência. Implemente moviesWithActor :: [Movie] -> String -> [Movie], preservando a ordem dos filmes em que o ator participou.

Haskell
type Movie = (String, [String])
myMovies :: [Movie]
myMovies = [("Titanic",["Kate Winslet","Leonardo DiCaprio"]),("Revolutionary Road",["Kate Winslet","Leonardo DiCaprio"]),("Elektra ",["Jennifer Garner"]),("The Great Gatsby",["Leonardo DiCaprio"])]
delAll :: Eq a => a -> [a] -> [a]
delAll x = filter (/= x)
uniqueVals :: Eq a => [a] -> [a]
uniqueVals [] = []
uniqueVals (x:xs) = x : uniqueVals (delAll x xs)
moviesWithActor :: [Movie] -> String -> [Movie]
moviesWithActor = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ordem
    Código do teste
    main = print (moviesWithActor [("A",["X"]),("B",[]),("C",["X"])] "X")
    Esperado:
    [("A",["X"]),("C",["X"])]
  2. Vazia
    Código do teste
    main = print (moviesWithActor [] "X")
    Esperado:
    []

Solução
moviesWithActor movies actor = filter (elem actor . snd) movies

filter preserva a ordem dos filmes e elem verifica a participação do ator.

Voltar à explicação
Reunir atores sem repetidosCódigo

Cada Movie é um par com o título e uma lista ordenada de atores. Podes usar delAll, que remove todas as ocorrências, e uniqueVals, que remove repetidos mantendo a primeira ocorrência. Implemente uniqueActors :: [Movie] -> [String], sem repetidos e pela ordem da primeira ocorrência.

Haskell
type Movie = (String, [String])
myMovies :: [Movie]
myMovies = [("Titanic",["Kate Winslet","Leonardo DiCaprio"]),("Revolutionary Road",["Kate Winslet","Leonardo DiCaprio"]),("Elektra ",["Jennifer Garner"]),("The Great Gatsby",["Leonardo DiCaprio"])]
delAll :: Eq a => a -> [a] -> [a]
delAll x = filter (/= x)
uniqueVals :: Eq a => [a] -> [a]
uniqueVals [] = []
uniqueVals (x:xs) = x : uniqueVals (delAll x xs)
uniqueActors :: [Movie] -> [String]
uniqueActors = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Repetidos
    Código do teste
    main = print (uniqueActors [("A",["X","Y"]),("B",["Y","Z"])])
    Esperado:
    ["X","Y","Z"]
  2. Vazia
    Código do teste
    main = print (uniqueActors [])
    Esperado:
    []

Solução
uniqueActors = uniqueVals . concatMap snd

concatMap snd concatena as listas de atores e uniqueVals remove as ocorrências posteriores.

Voltar à explicação
Contar filmes por atorCódigo

Cada Movie é um par com o título e uma lista ordenada de atores. Podes usar delAll, que remove todas as ocorrências, e uniqueVals, que remove repetidos mantendo a primeira ocorrência. Implemente actorFrequencies :: [Movie] -> [(String, Int)], contando filmes por ator e mantendo a ordem da primeira ocorrência, sem ordenar por frequência.

Haskell
type Movie = (String, [String])
myMovies :: [Movie]
myMovies = [("Titanic",["Kate Winslet","Leonardo DiCaprio"]),("Revolutionary Road",["Kate Winslet","Leonardo DiCaprio"]),("Elektra ",["Jennifer Garner"]),("The Great Gatsby",["Leonardo DiCaprio"])]
delAll :: Eq a => a -> [a] -> [a]
delAll x = filter (/= x)
uniqueVals :: Eq a => [a] -> [a]
uniqueVals [] = []
uniqueVals (x:xs) = x : uniqueVals (delAll x xs)
actorFrequencies :: [Movie] -> [(String, Int)]
actorFrequencies = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Um filme conta uma vez
    Código do teste
    main = print (actorFrequencies [("A",["X","X","Y"]),("B",["Y"])])
    Esperado:
    [("X",1),("Y",2)]
  2. Vazia
    Código do teste
    main = print (actorFrequencies [])
    Esperado:
    []

Solução
actorFrequencies ms = [(a, length [() | (_,as) <- ms, a `elem` as]) | a <- uniqueVals (concatMap snd ms)]

Para cada ator distinto, conta os filmes que o contêm; repetições no mesmo filme não acrescentam filmes. A contagem considera cada filme uma única vez.

Voltar à explicação
Propriedades das classes de tiposEscolha múltipla

Qual das seguintes afirmações sobre typeclasses está errada?

A tua resposta

Solução

Ord exige Eq como superclasse; a afirmação inversa está errada.

  • Ord é uma typeclass para tipos que suportam o operador <=.. Ord disponibiliza comparação ordenada.
  • Eq é uma subclasse de Ord.. É Ord que exige Eq como superclasse, e não o inverso.
  • Float faz parte da typeclass Fractional.. Float é instância de Fractional.
  • Int faz parte da typeclass Integral.. Int é instância de Integral.
  • Um tipo pode pertencer a três typeclasses diferentes.. Um tipo pode ser instância de várias classes.
Voltar à explicação
Tipo de uma compreensão com índicesEscolha múltipla

Indique um tipo possível para [ (n, x, x !! n) | n <- ls ].

A tua resposta

Solução

O índice de (!!) é Int e o resultado tem o tipo de um elemento da lista.

  • [(Int, [Char], [Char])]. Indexar [Char] devolve Char, não [Char].
  • ([Int], [String], String). A compreensão devolve uma lista de triplos.
  • [(Int, [Int], Int)]. O índice é Int e indexar [Int] devolve Int.
  • [(Int, String, String)]. Indexar String devolve Char, não String.
Voltar à explicação
Contar elementos por decrementosCódigo

Reimplemente funcX = foldl (\acc _ -> pred acc) 0 sem usar funções da família dos folds, incluindo foldr, foldl, foldr1 e scanr.

Haskell
funcX :: [a] -> Int
funcX = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Vazia
    Código do teste
    main = print (funcX ([] :: [Int]))
    Esperado:
    0
  2. Três
    Código do teste
    main = print (funcX [1,2,3])
    Esperado:
    -3

Solução
funcX [] = 0
funcX (_:xs) = pred (funcX xs)

Cada elemento decrementa uma vez; a lista vazia começa em zero.

Voltar à explicação
Comparar elementos em posições paresCódigo

Usando zip, defina evenPos para duas listas possivelmente de comprimentos diferentes. Devolva pares de elementos diferentes nas mesmas posições pares, contadas a partir de zero. Exemplos: evenPos [1,2,3,4,5] [5,4,3,2,1] = [(1,5),(5,1)]; evenPos "banana" "batata" = [('n','t'),('n','t')].

Haskell
evenPos :: Eq a => [a] -> [a] -> [(a,a)]
evenPos = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo
    Código do teste
    main = print (evenPos [1,2,3,4,5] [5,4,3,2,1])
    Esperado:
    [(1,5),(5,1)]
  2. Comprimentos
    Código do teste
    main = print (evenPos [1,2,3] [9])
    Esperado:
    [(1,9)]

Solução
evenPos xs ys = [(x,y) | (i,(x,y)) <- zip [0..] (zip xs ys), even i, x /= y]

zip termina na lista mais curta; o índice seleciona posições pares e x /= y exclui valores iguais.

Voltar à explicação
Gerar uma sequência por recorrênciaCódigo

Defina a lista infinita list para a₀ = 0, a₁ = 1, aₙ = 3 × aₙ₋₁ − 2 × aₙ₋₂ para n > 1. Segue a recorrência para calcular os termos.

Haskell
list :: [Integer]
list = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Primeiros termos
    Código do teste
    main = print (take 6 list)
    Esperado:
    [0,1,3,7,15,31]
  2. Prefixo vazio
    Código do teste
    main = print (take 0 list)
    Esperado:
    []

Solução
list = 0 : 1 : zipWith (\a b -> 3*b - 2*a) list (tail list)

A recorrência produz 0, 1, 3, 7, 15, 31. zipWith combina cada par de termos consecutivos.

Voltar à explicação
Avaliar proposições lógicasCódigo

Considere data Prop = Const Bool | Neg Prop | Conj Prop Prop | Disj Prop Prop | Impl Prop Prop. Defina recursivamente valor :: Prop -> Bool para calcular o valor lógico.

Haskell
data Prop = Const Bool | Neg Prop | Conj Prop Prop | Disj Prop Prop | Impl Prop Prop
valor :: Prop -> Bool
valor = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Implicação falsa
    Código do teste
    main = print (valor (Impl (Const True) (Const False)))
    Esperado:
    False
  2. Expressão
    Código do teste
    main = print (valor (Conj (Neg (Const False)) (Disj (Const False) (Const True))))
    Esperado:
    True

Solução
valor (Const b) = b
valor (Neg p) = not (valor p)
valor (Conj p q) = valor p && valor q
valor (Disj p q) = valor p || valor q
valor (Impl p q) = not (valor p) || valor q

A avaliação segue os construtores. A implicação p → q equivale a não p ou q.

Voltar à explicação

Recursão e transformação de estruturas

Tipo de uma função sobre paresEscolha múltipla

Considere f (x:xs, y:ys) = (2*x+y) : f (xs, ys); f _ = []. Qual é um tipo admissível?

A tua resposta

Solução

A função recebe um par de listas e devolve uma lista de números.

  • a. ([Float], [Float]) -> [Float]. A função recebe um par de listas e devolve uma lista de números.
  • b. ([Float], [Float]) -> Float. A função recebe um par de listas e devolve uma lista de números.
  • c. [Float] -> [Float] -> [Float]. A função recebe um par de listas e devolve uma lista de números.
  • d. ([Int] -> [Int]) -> [Int]. A função recebe um par de listas e devolve uma lista de números.
Voltar à explicação
Representar listasEscolha múltipla

Qual das definições é isomorfa a [Float]?

A tua resposta

Solução

Uma lista é vazia ou contém uma cabeça Float e outra lista.

  • a. data List = Empty | Cons Float List. Uma lista é vazia ou contém uma cabeça Float e outra lista.
  • b. data List = Last Float | Cons List List. Uma lista é vazia ou contém uma cabeça Float e outra lista.
  • c. data List = Empty | Cons Float Float. Uma lista é vazia ou contém uma cabeça Float e outra lista.
  • d. data List = Last Float | Cons Float List. Uma lista é vazia ou contém uma cabeça Float e outra lista.
Voltar à explicação
Construir expressõesEscolha múltipla

Considere data Expr = Num Int | Add Expr Expr | Mul Expr Expr. Qual representa (1+2)*(3*4)?

A tua resposta

Solução

Cada operação recebe duas expressões e cada inteiro é embrulhado em Num.

  • a. Mul (Add 1) (Add 2) (Mul 3) (Mul 4). Cada operação recebe duas expressões e cada inteiro é embrulhado em Num.
  • b. Mul (Add (Num 1) (Num 2)) (Num 3) (Num 4). Cada operação recebe duas expressões e cada inteiro é embrulhado em Num.
  • c. Mul (Mul (Num 1) (Num 2)) (Add (Num 3) (Num 4)). Cada operação recebe duas expressões e cada inteiro é embrulhado em Num.
  • d. Mul (Add (Num 1) (Num 2)) (Mul (Num 3) (Num 4)). Cada operação recebe duas expressões e cada inteiro é embrulhado em Num.
Voltar à explicação
Tipo de uma ação de leituraEscolha múltipla

Considere act end = do { x <- getChar; if x /= end then do { xs <- act end; return (x:xs) } else return [] }. Qual o tipo mais geral?

A tua resposta

Solução

getChar fixa os elementos e o terminador como Char; a leitura é uma ação IO.

  • a. IO [Char]. getChar fixa os elementos e o terminador como Char; a leitura é uma ação IO.
  • b. IO (Char -> [Char]). getChar fixa os elementos e o terminador como Char; a leitura é uma ação IO.
  • c. Char -> IO [Char]. getChar fixa os elementos e o terminador como Char; a leitura é uma ação IO.
  • d. Eq a => a -> IO [a]. getChar fixa os elementos e o terminador como Char; a leitura é uma ação IO.
Voltar à explicação
Par de funçõesEscolha múltipla

Qual expressão admite o tipo (String -> String, [Int -> Int])?

A tua resposta

Solução

reverse transforma uma String e os dois elementos da lista são funções Int -> Int.

  • a. (reverse, [\x -> x, \y -> 2*y]). reverse transforma uma String e os dois elementos da lista são funções Int -> Int.
  • b. (concat, [\x -> x+1, \y -> y-1]). reverse transforma uma String e os dois elementos da lista são funções Int -> Int.
  • c. ((++ "!!"), map (+1)). reverse transforma uma String e os dois elementos da lista são funções Int -> Int.
  • d. ((++), \x -> [x+1, x-1]). reverse transforma uma String e os dois elementos da lista são funções Int -> Int.
Voltar à explicação
Versão não curriedEscolha múltipla

Qual o tipo da versão não curried de g x y z = x+y*z?

A tua resposta

Solução

A versão pedida recebe os três argumentos num só triplo.

  • a. Num a => (a, a, a) -> a. A versão pedida recebe os três argumentos num só triplo.
  • b. Num a => (((a -> a) -> a) -> a) -> a. A versão pedida recebe os três argumentos num só triplo.
  • c. Num a => (a, a) -> (a, a). A versão pedida recebe os três argumentos num só triplo.
  • d. Num a => a -> (a -> (a -> a)). A versão pedida recebe os três argumentos num só triplo.
Voltar à explicação
Contar valores positivosEscolha múltipla

O que calcula h xss = length [x | xs <- xss, x <- xs, x > 0], para h :: [[Int]] -> Int?

A tua resposta

Solução

Os dois geradores percorrem cada elemento e a guarda conserva os positivos.

  • a. O número de valores positivos na matriz. Os dois geradores percorrem cada elemento e a guarda conserva os positivos.
  • b. O número de linhas em que todos os valores são positivos. Os dois geradores percorrem cada elemento e a guarda conserva os positivos.
  • c. O número de linhas com algum valor positivo. Os dois geradores percorrem cada elemento e a guarda conserva os positivos.
  • d. O número total de valores. Os dois geradores percorrem cada elemento e a guarda conserva os positivos.
Voltar à explicação
Compreensão e ordemEscolha múltipla

Considere j [] = []; j (x:xs) | even x = div x 2 : j xs | otherwise = (3*x+1) : j xs. Qual definição é equivalente?

A tua resposta

Solução

A condição transforma cada elemento sem mudar a ordem.

  • a. j xs = [div x 2 | x <- xs, even x] ++ [3*x+1 | x <- xs, otherwise]. A condição transforma cada elemento sem mudar a ordem.
  • b. j xs = [if even x then div x 2 else 3*x+1 | x <- xs]. A condição transforma cada elemento sem mudar a ordem.
  • c. j xs = [div x 2 | x <- xs, even x] ++ [3*x+1 | x <- xs, not (even x)]. A condição transforma cada elemento sem mudar a ordem.
  • d. j xs = sum [if even x then div x 2 else 3*x+1 | x <- xs]. A condição transforma cada elemento sem mudar a ordem.
Voltar à explicação
Geradores infinitosEscolha múltipla

O que é efetivamente produzido por [x/y | x <- [1..], y <- [1..]]?

A tua resposta

Solução

O gerador interior é infinito, pelo que nunca se avança de x = 1.

  • a. Todas as frações x/1 com inteiro x >= 1. O gerador interior é infinito, pelo que nunca se avança de x = 1.
  • b. Todas as frações 1/y com inteiro y >= 1. O gerador interior é infinito, pelo que nunca se avança de x = 1.
  • c. Todas as frações x/y com inteiros x,y >= 1. O gerador interior é infinito, pelo que nunca se avança de x = 1.
  • d. Todas as frações x/x com inteiro x >= 1. O gerador interior é infinito, pelo que nunca se avança de x = 1.
Voltar à explicação
Filtrar e transformarEscolha múltipla

Considere f :: [String] -> [String]; f [] = []; f (xs:rest) | null xs = f rest | otherwise = (xs ++ "!!") : f rest. Qual é equivalente?

A tua resposta

Solução

É necessário excluir as strings vazias antes de acrescentar os pontos.

  • a. f = map (++"!!") . filter (not . null). É necessário excluir as strings vazias antes de acrescentar os pontos.
  • b. f = filter null . map (++"!!"). É necessário excluir as strings vazias antes de acrescentar os pontos.
  • c. f = map (++"!!") . filter null. É necessário excluir as strings vazias antes de acrescentar os pontos.
  • d. f = filter (not . null) . map (++"!!"). É necessário excluir as strings vazias antes de acrescentar os pontos.
Voltar à explicação
Map aninhadoEscolha múltipla

Qual é equivalente a f x = map (map (+1)) x?

A tua resposta

Solução

Cada linha mantém-se separada e cada elemento aumenta uma unidade.

  • a. f x = [[z+1 | y <- x, z <- y]]. Cada linha mantém-se separada e cada elemento aumenta uma unidade.
  • b. f x = [[z+1 | z <- y] | y <- x]. Cada linha mantém-se separada e cada elemento aumenta uma unidade.
  • c. f x = [[z+2 | z <- y] | y <- x]. Cada linha mantém-se separada e cada elemento aumenta uma unidade.
  • d. f x = [[y+1 | y <- x]]. Cada linha mantém-se separada e cada elemento aumenta uma unidade.
Voltar à explicação
Acumulador e foldEscolha múltipla

Considere f xs = g xs [] where { g [] acc = acc; g (x:xs) acc = g xs (x:x:acc) }. Qual é equivalente?

A tua resposta

Solução

foldl atualiza o acumulador da esquerda para a direita, antepondo duas cópias.

  • a. f = foldl (\acc x -> [x,x]:acc) []. foldl atualiza o acumulador da esquerda para a direita, antepondo duas cópias.
  • b. f = foldl (\acc x -> x:x:acc) []. foldl atualiza o acumulador da esquerda para a direita, antepondo duas cópias.
  • c. f = foldr (\x acc -> [x,x]:acc) []. foldl atualiza o acumulador da esquerda para a direita, antepondo duas cópias.
  • d. f = foldr (\x acc -> x:x:acc) []. foldl atualiza o acumulador da esquerda para a direita, antepondo duas cópias.
Voltar à explicação
Dígitos numa baseCódigo

Defina getDigits :: Int -> Int -> [Int] por divisões inteiras sucessivas. Assuma n >= 0 e 2 <= b <= 10. Devolva os dígitos do menos para o mais significativo. Exemplos: getDigits 2 3 = [1,1]; getDigits 10 123 = [3,2,1]; getDigits 2 11 = [1,1,0,1]; getDigits 2 0 = [].

Haskell
getDigits :: Int -> Int -> [Int]
getDigits = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Binário
    Código do teste
    main = print (getDigits 2 11)
    Esperado:
    [1,1,0,1]
  2. Decimal
    Código do teste
    main = print (getDigits 10 123)
    Esperado:
    [3,2,1]
  3. Zero
    Código do teste
    main = print (getDigits 2 0)
    Esperado:
    []

Solução
getDigits :: Int -> Int -> [Int]
getDigits _ 0 = []
getDigits b n = n `mod` b : getDigits b (n `div` b)

O resto dá o próximo dígito; o quociente elimina-o.

Voltar à explicação
Remover pela comparaçãoCódigo

Defina deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a], removendo apenas o primeiro elemento que o predicado considera igual ao argumento. Exemplos: deleteBy (\x y -> x `mod` 2 == y `mod` 2) 1 [3,4,5] = [4,5]; deleteBy (==) 'x' "YXXXx" = "YXXX".

Haskell
deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
deleteBy = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Paridade
    Código do teste
    main = print (deleteBy (\x y -> x `mod` 2 == y `mod` 2) 1 [3,4,5])
    Esperado:
    [4,5]
  2. Caráter
    Código do teste
    main = print (deleteBy (==) 'x' "YXXXx")
    Esperado:
    "YXXX"
  3. Ausente
    Código do teste
    main = print (deleteBy (==) 2 [1,3])
    Esperado:
    [1,3]

Solução
deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
deleteBy _ _ [] = []
deleteBy eq x (y:ys) | eq x y = ys
                     | otherwise = y : deleteBy eq x ys

Ao encontrar a primeira correspondência, devolve a cauda sem continuar a remover.

Voltar à explicação
Janelas deslizantesCódigo

Defina slidingWindow :: Int -> [a] -> [[a]], com todas as fatias consecutivas de comprimento k. Assuma k <= length xs. Sugestão: recursão e take. Exemplos: slidingWindow 3 [1..10] = [[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10]]; slidingWindow 2 "ABCD" = ["AB","BC","CD"]; slidingWindow 4 "ABCD" = ["ABCD"]. Para k = 0, considere uma janela vazia em cada posição, incluindo o fim.

Haskell
slidingWindow :: Int -> [a] -> [[a]]
slidingWindow = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Texto
    Código do teste
    main = print (slidingWindow 2 "ABCD")
    Esperado:
    ["AB","BC","CD"]
  2. Inteira
    Código do teste
    main = print (slidingWindow 4 "ABCD")
    Esperado:
    ["ABCD"]
  3. Zero
    Código do teste
    main = print (slidingWindow 0 [1,2])
    Esperado:
    [[],[],[]]

Solução
slidingWindow :: Int -> [a] -> [[a]]
slidingWindow k xs | k < 0 = []
                   | k == 0 = replicate (length xs + 1) []
                   | length xs < k = []
                   | otherwise = take k xs : slidingWindow k (tail xs)

Cada chamada avança uma posição. O caso k = 0 foi explicitado, pois não estava definido pelo pedido.

Voltar à explicação
Arestas e adjacênciasCódigo

Uma aresta (x,y,d) liga x a y com distância d. Uma lista de adjacências associa a cada nó os pares (destino, distância). Defina edgesToAdjacencies :: EdgeList -> AdjList, com uma entrada por nó, incluindo nós que só aparecem como destino. A ordem das listas não importa. Exemplo: [("A","D",10),("B","C",15),("A","C",5),("C","A",10),("B","D",20)] corresponde a [("A",[("D",10),("C",5)]),("B",[("C",15),("D",20)]),("C",[("A",10)]),("D",[])]. Pode usar nub, que remove duplicados.

Haskell
import Data.List (nub)
import qualified Data.List
type Node = String
type Dist = Int
type EdgeList = [(Node,Node,Dist)]
type AdjList = [(Node,[(Node,Dist)])]
edgesToAdjacencies :: EdgeList -> AdjList
edgesToAdjacencies = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Grafo
    Código do teste
    main = print (let norm = Data.List.sort . map (\(n,as) -> (n,Data.List.sort as)) in norm (edgesToAdjacencies [("A","D",10),("B","C",15),("A","C",5),("C","A",10),("B","D",20)]))
    Esperado:
    [("A",[("C",5),("D",10)]),("B",[("C",15),("D",20)]),("C",[("A",10)]),("D",[])]
  2. Vazio
    Código do teste
    main = print (edgesToAdjacencies [])
    Esperado:
    []

Solução
import Data.List (nub)
import qualified Data.List
type Node = String
type Dist = Int
type EdgeList = [(Node,Node,Dist)]
type AdjList = [(Node,[(Node,Dist)])]
edgesToAdjacencies :: EdgeList -> AdjList
edgesToAdjacencies es = [(n, [(y,d) | (x,y,d) <- es, x == n]) | n <- nub ([x | (x,_,_) <- es] ++ [y | (_,y,_) <- es])]

Recolhem-se ambos os extremos, sem repetição, e depois as arestas que partem de cada nó.

Voltar à explicação
Criar uma trieCódigo

Uma trie data Trie = Node [(Char,Trie)] deriving Show guarda filhos etiquetados por caracteres; Node [] representa a string vazia. Defina recursivamente makeTrie :: String -> Trie que cria os prefixos de uma string. Exemplos: makeTrie "" = Node []; makeTrie "a" = Node [('a',Node [])]; makeTrie "abc" = Node [('a',Node [('b',Node [('c',Node [])])])].

Haskell
import qualified Data.List
data Trie = Node [(Char,Trie)] deriving Show
makeTrie :: String -> Trie
makeTrie = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Vazia
    Código do teste
    main = print (show (makeTrie ""))
    Esperado:
    "Node []"
  2. Caminho
    Código do teste
    main = print (let norm (Node cs) = Node (Data.List.sortOn fst [(c,norm t) | (c,t) <- cs]) in show (norm (makeTrie "abc")))
    Esperado:
    "Node [('a',Node [('b',Node [('c',Node [])])])]"

Solução
data Trie = Node [(Char,Trie)] deriving Show
makeTrie :: String -> Trie
makeTrie [] = Node []
makeTrie (x:xs) = Node [(x,makeTrie xs)]

Cada carácter cria um filho, e a string vazia termina o caminho.

Voltar à explicação
Inserir prefixos numa trieCódigo

Defina insert :: String -> Trie -> Trie para inserir todos os prefixos, sem rótulos repetidos entre filhos. A ordem dos filhos não importa. Por exemplo, inserir "abc" em Node [] cria o caminho a,b,c; inserir depois "abd" partilha a e b e cria os filhos c e d.

Haskell
import qualified Data.List
data Trie = Node [(Char,Trie)] deriving Show
insert :: String -> Trie -> Trie
insert = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Dois ramos
    Código do teste
    main = print (let norm (Node cs) = Node (Data.List.sortOn fst [(c,norm t) | (c,t) <- cs]) in show (norm (insert "abd" (insert "abc" (Node [])))))
    Esperado:
    "Node [('a',Node [('b',Node [('c',Node []),('d',Node [])])])]"
  2. Vazia
    Código do teste
    main = print (show (insert "" (Node [])))
    Esperado:
    "Node []"

Solução
data Trie = Node [(Char,Trie)] deriving Show
insert :: String -> Trie -> Trie
insert [] t = t
insert (x:xs) (Node cs) = Node (go cs)
  where
    go [] = [(x,insert xs (Node []))]
    go ((c,t):rest) | c == x = (c,insert xs t):rest
                    | otherwise = (c,t):go rest

Segue o filho existente ou cria-o; os restantes filhos permanecem intactos.

Voltar à explicação

Cálculo, tipos e indução

Cons e concatenaçãoAutoavaliação

Indique o resultado de "abc":[[]] ++ "dce":[].

Solução
["abc",[],"dce"]

(:) acrescenta uma lista à cabeça; (++) junta as listas exteriores.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Cauda de listasAutoavaliação

Indique o resultado de tail ([1]:[2]:[]:[3]:[4]:[]).

Solução
[[2],[],[3],[4]]

tail remove apenas o primeiro elemento da lista exterior.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Indexação duplaAutoavaliação

Indique o resultado de [[1,2,3,4],[5,6,7,8],[9,10,11,12]] !! 2 !! 1.

Solução
10

Os índices começam em zero: escolhe a terceira linha e o seu segundo elemento.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Mapear uma multiplicaçãoAutoavaliação

Indique o resultado de map (\x -> x*2) [1,2,3,4].

Solução
[2,4,6,8]

map multiplica cada elemento por dois, preservando a ordem.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Diferenças com zipWithAutoavaliação

Indique o resultado de zipWith (-) [1,3..10] [0,3..].

Solução
[1,0,-1,-2,-3]

As listas começam por [1,3,5,7,9] e [0,3,6,9,12]. zipWith termina com a primeira.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Remover um prefixoAutoavaliação

Indique o resultado de dropWhile (<6) [2..10].

Solução
[6,7,8,9,10]

Remove o prefixo que satisfaz (<6); o primeiro 6 fica.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Filtrar uma compreensãoAutoavaliação

Indique o resultado de [x | x <- [1..10], x <= 6, x >= 4].

Solução
[4,5,6]

As duas condições têm de ser verdadeiras.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Uma sequência alternadaCódigo

Defina por compreensão a lista infinita [-2,4,-8,16,-32,64,-128,256,...].

Haskell
alternada :: [Integer]
alternada = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Oito termos
    Código do teste
    main = print (take 8 alternada)
    Esperado:
    [-2,4,-8,16,-32,64,-128,256]
  2. Prefixo vazio
    Código do teste
    main = print (take 0 alternada)
    Esperado:
    []

Solução
alternada = [(-1)^x * 2^x | x <- [1..]]

O índice começa em 1, a potência de dois cresce e (-1)^x alterna o sinal.

Voltar à explicação
Terminar no padrão singletonAutoavaliação

Avalie h = let { f [x] = 1; f (y:z) = y * f z } in f [1,2,3,4,5].

Solução
24

O caso [5] devolve 1: o produto é 1 × 2 × 3 × 4 × 1.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Tipo de uma seleçãoAutoavaliação

Indique um tipo admissível para f xs = head (tail xs).

Solução
[a] -> a

tail conserva o tipo da lista; head devolve um elemento. A função exige pelo menos dois elementos para terminar sem erro.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Tipo de um parAutoavaliação

Indique o tipo mais geral de ([False,True], ['0','1']).

Solução
([Bool], String)

O primeiro elemento é uma lista de Bool; o segundo é [Char], também chamado String.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Tipo de uma avaliação estruturalAutoavaliação

Considere data E a = V a | Op (E a) (E a); aval (V v) f g = f v; aval (Op e1 e2) f g = g (aval e1 f g) (aval e2 f g). Dê um tipo admissível de aval quando f :: a -> Bool.

Solução
E a -> (a -> Bool) -> (Bool -> Bool -> Bool) -> Bool

f transforma uma folha em Bool; g combina os dois resultados Bool de cada Op.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Tipo de uma concatenaçãoAutoavaliação

Indique o tipo mais geral de foldr (++) [].

Solução
[[a]] -> [a]

(++) combina uma lista com o acumulador, que também é uma lista. A entrada é, por isso, uma lista de listas.

Confere a tua resposta:

  • Compare o resultado e a justificação com a solução.
Voltar à explicação
Aprovação por notaCódigo

Defina aprov para uma lista de notas, devolvendo A para nota >= 15 e R caso contrário. Exemplos: aprov [2,8,15,9] = "RRAR" e aprov [12,10,17,8,19] = "RRARA". Pode usar o prelúdio ou compreensão, mas não recursão direta.

Haskell
aprov :: [Int] -> String
aprov = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Primeira
    Código do teste
    main = print (aprov [2,8,15,9])
    Esperado:
    "RRAR"
  2. Segunda
    Código do teste
    main = print (aprov [12,10,17,8,19])
    Esperado:
    "RRARA"
  3. Vazia
    Código do teste
    main = print (aprov [])
    Esperado:
    ""

Solução
aprov :: [Int] -> String
aprov xs = [if x >= 15 then 'A' else 'R' | x <- xs]

Cada nota é classificada independentemente. Os testes não verificam a ausência de recursão direta.

Voltar à explicação
Contar alunos injustiçadosCódigo

Defina injust para contar os alunos que passariam com nota >= 10 mas são reprovados pelo limiar 15. Exemplos: injust [2,8,15,9] = 0 e injust [12,10,17,8,19] = 2. Use o prelúdio ou compreensão, sem recursão direta.

Haskell
injust :: [Int] -> Int
injust = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Nenhum
    Código do teste
    main = print (injust [2,8,15,9])
    Esperado:
    0
  2. Dois
    Código do teste
    main = print (injust [12,10,17,8,19])
    Esperado:
    2
  3. Limites
    Código do teste
    main = print (injust [9,10,14,15])
    Esperado:
    2

Solução
injust :: [Int] -> Int
injust xs = length [x | x <- xs, x >= 10, x < 15]

O intervalo de notas injustiçadas inclui 10 e exclui 15. Os testes não verificam o método.

Voltar à explicação
Lista infinita de repetiçõesCódigo

Defina recursivamente repete, que recebe a e produz [[],[a],[a,a],[a,a,a],...].

Haskell
repete :: a -> [[a]]
repete = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Prefixo
    Código do teste
    main = print (take 4 (repete 'x'))
    Esperado:
    ["","x","xx","xxx"]
  2. Números
    Código do teste
    main = print (take 3 (repete (2::Int)))
    Esperado:
    [[],[2],[2,2]]

Solução
repete :: a -> [[a]]
repete x = [] : map (x:) (repete x)

A lista começa vazia; acrescentar x a cada elemento produz os comprimentos seguintes. Os testes não verificam a recursão.

Voltar à explicação
Máximo lido da entradaCódigo

Escreva maximo :: IO (), que lê naturais, um por linha, até ao terminador 0 e escreve o máximo. Pode usar maximum. Se o primeiro valor for 0, escreva 0. Para testar no navegador, os testes fornecem as ações de leitura e escrita. Usa getLine, readLn, getContents, putStr, putStrLn ou print sem prefixo de módulo, mantendo os imports iniciais.

Haskell
import Prelude hiding (getLine, readLn, getContents, putStr, putStrLn, print, interact)
import qualified Prelude
import Data.IORef
import System.IO.Unsafe (unsafePerformIO)

maximo :: IO ()
maximo = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Sequência
    Código do teste
    testInput :: IORef [String]
    testInput = unsafePerformIO (newIORef ["3","8","2","0"])
    {-# NOINLINE testInput #-}
    testOutput :: IORef String
    testOutput = unsafePerformIO (newIORef "")
    {-# NOINLINE testOutput #-}
    getLine :: IO String
    getLine = do
      xs <- readIORef testInput
      case xs of
        [] -> ioError (userError "Entrada esgotada")
        (x:rest) -> writeIORef testInput rest >> return x
    readLn :: Read a => IO a
    readLn = read <$> getLine
    getContents :: IO String
    getContents = do
      xs <- readIORef testInput
      writeIORef testInput []
      return (unlines xs)
    putStr :: String -> IO ()
    putStr s = modifyIORef' testOutput (++ s)
    putStrLn :: String -> IO ()
    putStrLn s = putStr (s ++ "\n")
    print :: Show a => a -> IO ()
    print = putStrLn . show
    interact :: (String -> String) -> IO ()
    interact f = getContents >>= putStr . f
    main :: IO ()
    main = do
      maximo
      captured <- readIORef testOutput
      Prelude.print captured
    Esperado:
    "8\n"
  2. Imediato
    Código do teste
    testInput :: IORef [String]
    testInput = unsafePerformIO (newIORef ["0"])
    {-# NOINLINE testInput #-}
    testOutput :: IORef String
    testOutput = unsafePerformIO (newIORef "")
    {-# NOINLINE testOutput #-}
    getLine :: IO String
    getLine = do
      xs <- readIORef testInput
      case xs of
        [] -> ioError (userError "Entrada esgotada")
        (x:rest) -> writeIORef testInput rest >> return x
    readLn :: Read a => IO a
    readLn = read <$> getLine
    getContents :: IO String
    getContents = do
      xs <- readIORef testInput
      writeIORef testInput []
      return (unlines xs)
    putStr :: String -> IO ()
    putStr s = modifyIORef' testOutput (++ s)
    putStrLn :: String -> IO ()
    putStrLn s = putStr (s ++ "\n")
    print :: Show a => a -> IO ()
    print = putStrLn . show
    interact :: (String -> String) -> IO ()
    interact f = getContents >>= putStr . f
    main :: IO ()
    main = do
      maximo
      captured <- readIORef testOutput
      Prelude.print captured
    Esperado:
    "0\n"

Solução
maximo :: IO ()
maximo = loop 0
  where
    loop :: Int -> IO ()
    loop m = do
      n <- readLn
      if n == 0 then print m else loop (max m n)

O acumulador guarda o maior natural lido; o zero termina a leitura. A sequência vazia tem resultado convencionado como 0.

Voltar à explicação
Composição recursivaCódigo

Defina recursivamente compL :: [a -> a] -> a -> a. Por exemplo compL [f,g,h] v = f (g (h v)).

Haskell
compL :: [a -> a] -> a -> a
compL = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ordem
    Código do teste
    main = print (compL [(+1),(*2)] (3::Int))
    Esperado:
    7
  2. Vazia
    Código do teste
    main = print (compL [] (4::Int))
    Esperado:
    4

Solução
compL :: [a -> a] -> a -> a
compL [] v = v
compL (f:fs) v = f (compL fs v)

A cauda é aplicada primeiro, preservando a ordem da composição. Os testes não exigem recursão.

Voltar à explicação
Composição de ordem superiorCódigo

Defina compL :: [a -> a] -> a -> a usando uma função de ordem superior, de modo que compL [f,g,h] v = f (g (h v)).

Haskell
compL :: [a -> a] -> a -> a
compL = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ordem
    Código do teste
    main = print (compL [(+1),(*2)] (3::Int))
    Esperado:
    7
  2. Vazia
    Código do teste
    main = print (compL [] (4::Int))
    Esperado:
    4

Solução
compL :: [a -> a] -> a -> a
compL fs = foldr (.) id fs

foldr compõe da direita para a esquerda e id é o caso vazio. Os testes não exigem o método.

Voltar à explicação
Somar uma árvoreCódigo

Para data Arv a = Vazia | No a (Arv a) (Arv a), defina soma para calcular a soma dos valores dos nós.

Haskell
data Arv a = Vazia | No a (Arv a) (Arv a)
soma :: Num a => Arv a -> a
soma = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Árvore
    Código do teste
    main = print (soma (No 3 (No 2 Vazia Vazia) (No 5 Vazia Vazia)))
    Esperado:
    10
  2. Vazia
    Código do teste
    main = print (soma (Vazia :: Arv Int))
    Esperado:
    0

Solução
data Arv a = Vazia | No a (Arv a) (Arv a)
soma :: Num a => Arv a -> a
soma Vazia = 0
soma (No x e d) = x + soma e + soma d

A árvore vazia contribui zero; cada nó acrescenta o seu valor e as duas somas.

Voltar à explicação
Fold de uma árvoreCódigo

Para data Arv a = Vazia | No a (Arv a) (Arv a), defina foldtree análogo a foldr para árvores. A função de combinação tem tipo a -> b -> b -> b. Por exemplo, soma t = foldtree soma3 0 t, com soma3 x y z = x+y+z.

Haskell
data Arv a = Vazia | No a (Arv a) (Arv a)
foldtree :: (a -> b -> b -> b) -> b -> Arv a -> b
foldtree = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Soma
    Código do teste
    main = print (foldtree (\x y z -> x+y+z) 0 (No 3 (No 2 Vazia Vazia) (No 5 Vazia Vazia)))
    Esperado:
    10
  2. Estrutura
    Código do teste
    main = print (foldtree (\x y z -> x:y++z) [] (No 1 Vazia (No 2 Vazia Vazia)))
    Esperado:
    [1,2]

Solução
data Arv a = Vazia | No a (Arv a) (Arv a)
foldtree :: (a -> b -> b -> b) -> b -> Arv a -> b
foldtree _ z Vazia = z
foldtree f z (No x e d) = f x (foldtree f z e) (foldtree f z d)

O valor base substitui cada árvore vazia; f combina o nó com os dois resultados.

Voltar à explicação
Indução sobre uma árvoreAutoavaliação

Para data Arv a = Vazia | No a (Arv a) (Arv a), considere soma Vazia = 0; soma (No x l r) = x + soma l + soma r; foldtree f z Vazia = z; foldtree f z (No x l r) = f x (foldtree f z l) (foldtree f z r). Mostre por indução que soma t = foldtree soma3 0 t, onde soma3 x y z = x+y+z.

Solução
Base: soma Vazia = 0 = foldtree soma3 0 Vazia.
Hipóteses: soma l = foldtree soma3 0 l e soma r = foldtree soma3 0 r.
Passo: foldtree soma3 0 (No x l r)
= soma3 x (foldtree soma3 0 l) (foldtree soma3 0 r)
= x + soma l + soma r
= soma (No x l r).

A indução segue os construtores e usa uma hipótese por subárvore.

Confere a tua resposta:

  • Compara cada passo com a resolução.
Voltar à explicação
Indução sobre uma concatenaçãoAutoavaliação

Mostre por indução em xs que foldr f v (xs ++ ys) = foldr f (foldr f v ys) xs. Pode usar as definições de (++) e foldr.

Solução
Base xs = []: foldr f v ([] ++ ys) = foldr f v ys = foldr f (foldr f v ys) [].
Hipótese: foldr f v (zs ++ ys) = foldr f (foldr f v ys) zs.
Passo xs = z:zs:
foldr f v ((z:zs) ++ ys)
= f z (foldr f v (zs ++ ys))
= f z (foldr f (foldr f v ys) zs)
= foldr f (foldr f v ys) (z:zs).

Expande a cabeça da lista e aplica a hipótese à cauda. Em cada igualdade, mantém o mesmo acumulador interior.

Confere a tua resposta:

  • Compara cada passo com a resolução.
Voltar à explicação

Funções, grafos e prefixos

Tipos de pares e funçõesEscolha múltipla

Qual das expressões admite o tipo ([Int] -> [Int], [Char])?

A tua resposta

Solução
(tail, head ["ABC"]) :: ([Int] -> [Int], [Char])

A especialização de tail aceita uma lista de inteiros e head da lista de strings devolve a string "ABC".

  • (tail, head ["ABC"]). tail pode ser especializada a [Int] -> [Int], e head devolve uma String.
  • (head, reverse "ABC"). head devolve um elemento, não uma lista de inteiros.
  • (reverse, tail ["ABC"]). O segundo elemento é uma lista de strings, não uma string.
  • ((++), tail "abc"). (++) recebe duas listas; não tem o tipo pedido para o primeiro elemento.
Voltar à explicação
Linhas de uma matriz booleanaEscolha múltipla

Considere f :: [[Bool]] -> Int; f xss = length [xs | xs <- xss, or xs]. O que calcula f?

A tua resposta

Solução
f [[False,True],[True,True],[]] == 2

or testa cada linha e length conta as linhas selecionadas. Uma linha vazia não é selecionada.

  • Número de entradas True. A compreensão seleciona linhas inteiras.
  • Número de linhas só com valores True. or exige pelo menos um True.
  • Número de entradas False. Não conta entradas individuais.
  • Número de linhas com pelo menos um True. or xs seleciona exatamente essas linhas.
Voltar à explicação
Compreensão de prefixosEscolha múltipla

Considere g :: Int -> [[Int]]; g n = [[1..i] | i <- [1..n]]. Qual é o resultado?

A tua resposta

Solução
g 4 == [[1],[1,2],[1,2,3],[1,2,3,4]]
g 0 == []

O gerador percorre os valores de i; para n inferior a 1, o intervalo é vazio.

  • Listas de comprimentos crescentes de 1 até n. Para cada i, [1..i] tem i elementos, quando n é positivo.
  • Listas de comprimentos decrescentes de n até 1. i cresce de 1 até n.
  • Listas todas com comprimento n. O comprimento é i.
  • Listas todas com comprimento 1. Só a primeira tem comprimento 1.
Voltar à explicação
Filtrar e elevar ao quadradoEscolha múltipla

Dada a definição h [] = []; h (x:xs) | x>0 = (x*x) : h xs | otherwise = h xs, qual a compreensão equivalente?

A tua resposta

Solução
h xs = [x*x | x <- xs, x>0]

A guarda seleciona apenas elementos positivos, preservando a sua ordem.

  • h xs = [if x>0 then x*x else 0 | x<-xs]. Acrescenta zeros para os valores excluídos.
  • h xs = [x*x | x<-xs, x>0] ++ [x | x<-xs, otherwise]. Acrescenta todos os valores originais.
  • h xs = [if x>0 then x*x else x | x<-xs]. Mantém os valores não positivos.
  • h xs = [x*x | x<-xs, x>0]. O predicado exclui os não positivos antes de formar o quadrado.
Voltar à explicação
Filtragem e composiçãoEscolha múltipla

Considere f :: [String] -> [String]; f [] = []; f (x:xs) | length x<=5 = f xs | otherwise = take 5 x : f xs. Qual é a definição equivalente?

A tua resposta

Solução
f = map (take 5) . filter ((>5) . length)

A composição aplica primeiro filter à entrada original e só depois map.

  • f = filter ((<=5).length) . map (take 5). Filtra depois de truncar, quando todas as strings têm comprimento até 5.
  • f = map (take 5) . filter ((<=5).length). Seleciona strings demasiado curtas.
  • f = filter ((>5).length) . map (take 5). Após truncar, nenhuma string tem comprimento superior a 5.
  • f = map (take 5) . filter ((>5).length). Primeiro seleciona as strings longas, depois trunca-as.
Voltar à explicação
Recursão e foldEscolha múltipla

Dada g [] = 0; g ((x,y):ps) = x*y - g ps, qual é a definição equivalente?

A tua resposta

Solução
g = foldr (\(x,y) r -> x*y-r) 0

foldr substitui a lista vazia por 0 e cada passo aplica a operação ao par e ao resultado da cauda.

  • g = foldr (\r (x,y) -> x*y-r) 0. foldr passa primeiro o elemento, não o acumulador.
  • g = foldr (\(x,y) r -> x*y-r) 0. O segundo argumento é o resultado recursivo.
  • g = foldl (\r (x,y) -> r-x*y) 0. Um fold à esquerda altera a associação das subtrações.
  • g = foldl (\r (x,y) -> x*y-r) 0. Um fold à esquerda processa os pares na ordem oposta à associação pedida.
Voltar à explicação
Contar primos numa lista infinitaEscolha múltipla

Considere primes = sieve [2..]; sieve (p:xs) = p : sieve [x | x<-xs, x `mod` p/=0]. Qual expressão conta os primos entre 10000 e 100000, inclusive?

A tua resposta

Solução
length (takeWhile (<=100000) $ dropWhile (<10000) primes)

Como primes é crescente, takeWhile produz uma lista finita. filter não pára ao encontrar valores superiores ao limite.

  • length (filter (\p -> 10000<=p && p<=100000) primes). filter continua a procurar numa lista infinita e length não termina.
  • length (take 100000 $ drop 10000 primes). take e drop usam números de elementos, não limites de valor.
  • length (takeWhile (<=100000) $ dropWhile (<10000) primes). Descarta os valores inferiores e termina ao ultrapassar o limite superior.
  • length (filter (<=100000) $ filter (>=1000) primes). Os filtros percorrem uma lista infinita e o limite inferior também está errado.
Voltar à explicação
Tipo recursivo de lista de paresEscolha múltipla

Qual definição representa a mesma estrutura que [(String,Int)]?

A tua resposta

Solução
data PairList = Empty | Cons String Int PairList

Cada nó corresponde a um par e à cauda da lista; o caso vazio não transporta dados.

  • data PairList = Empty | Cons String Int PairList. Empty representa [] e Cons guarda os dois campos e o resto.
  • data PairList = Empty Int | Cons String PairList. O caso vazio contém um Int e cada nó não tem um Int.
  • data PairList = Empty String Int | Cons Int PairList. Os campos do par não estão em cada nó.
  • data PairList = Empty String Int | Cons String Int PairList. O caso vazio tem campos adicionais.
Voltar à explicação
Comparar metades dos dígitosCódigo

Um inteiro é interessante se for positivo e a sua representação decimal se dividir em duas metades iguais, eventualmente com um dígito extra no meio. Por exemplo, 1213121, 5656 e 22 são interessantes; 12345 não é. Defina interesting :: Int -> Bool. Calcule os dígitos com uma função auxiliar recursiva e divisões inteiras, sem show.

Haskell
interesting :: Int -> Bool
interesting = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Metades pares e ímpares
    Código do teste
    main = print (map interesting [1213121,5656,22,12345])
    Esperado:
    [True,True,True,False]
  2. Positividade e um dígito
    Código do teste
    main = print (map interesting [-22,0,7])
    Esperado:
    [False,False,True]
  3. Zeros internos
    Código do teste
    main = print (map interesting [1010,1001,100100])
    Esperado:
    [True,False,True]

Solução
interesting :: Int -> Bool
interesting n = n > 0 && take h ds == drop (length ds - h) ds
  where
    ds = digits n []
    h = length ds `div` 2
    digits k acc
      | k <= 0 = acc
      | otherwise = digits (k `div` 10) ((k `mod` 10) : acc)

A extração constrói os dígitos da esquerda para a direita. Compara as primeiras e últimas metades, ignorando o dígito central quando existe. Um número positivo com um dígito tem duas metades vazias.

Voltar à explicação
Agrupar elementos consecutivosCódigo

Defina groupBy :: (a -> a -> Bool) -> [a] -> [[a]], que divide a lista em grupos consecutivos de valores iguais segundo a comparação dada. Não use Data.List. Exemplos: groupBy (==) "aaAccaa" = ["aa","A","cc","aa"]; groupBy (\x y -> toLower x==toLower y) "AabBbcCC" = ["Aa","bBb","cCC"].

Haskell
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Grupos consecutivos
    Código do teste
    main = print (groupBy (==) "aaAccaa")
    Esperado:
    ["aa","A","cc","aa"]
  2. Lista vazia
    Código do teste
    main = print (groupBy (==) ([] :: [Int]))
    Esperado:
    []
  3. Comparação com o primeiro
    Código do teste
    main = print (groupBy (\x y -> abs (x-y) <= 1) [1,2,3,3])
    Esperado:
    [[1,2],[3,3]]
  4. Sem distinguir maiúsculas
    Código do teste
    main = print (groupBy (\x y -> x == y || abs (fromEnum x - fromEnum y) == 32) "AabBbcCC")
    Esperado:
    ["Aa","bBb","cCC"]

Solução
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:matched) : groupBy eq rest
  where (matched, rest) = span (eq x) xs

span compara os elementos seguintes com o primeiro do grupo. O primeiro que falha inicia a próxima chamada.

Voltar à explicação
Intercalar listas ordenadasCódigo

Defina recursivamente merge :: Ord a => [a] -> [a] -> [a], que combina duas listas ascendentes numa lista ascendente com todos os valores. Percorra as duas listas numa única passagem recursiva. Exemplo: merge [1,4,5,7,9] [2,3,6,8,10] = [1,2,3,4,5,6,7,8,9,10].

Haskell
merge :: Ord a => [a] -> [a] -> [a]
merge = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo
    Código do teste
    main = print (merge [1,4,5,7,9] [2,3,6,8,10])
    Esperado:
    [1,2,3,4,5,6,7,8,9,10]
  2. Repetidos
    Código do teste
    main = print (merge [1,2,2] [2,3])
    Esperado:
    [1,2,2,2,3]
  3. Uma lista vazia
    Código do teste
    main = print (merge ([] :: [Int]) [1,3])
    Esperado:
    [1,3]

Solução
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
  | x <= y = x : merge xs (y:ys)
  | otherwise = y : merge (x:xs) ys

Escolhe a menor cabeça e avança apenas nessa lista. Quando uma termina, a outra já está ordenada e pode ser devolvida inteira.

Voltar à explicação
Ordenação por intercalaçãoCódigo

Defina recursivamente msort :: Ord a => [a] -> [a] usando merge sort: listas vazias ou singulares já estão ordenadas; divida as restantes em duas metades, ordene-as e combine-as com merge. Pode usar merge. Exemplo: msort [3,1,5,2,6,4,7,10,9,8] = [1,2,3,4,5,6,7,8,9,10].

Haskell
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
  | x <= y = x : merge xs (y:ys)
  | otherwise = y : merge (x:xs) ys

msort :: Ord a => [a] -> [a]
msort = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Exemplo
    Código do teste
    main = print (msort [3,1,5,2,6,4,7,10,9,8])
    Esperado:
    [1,2,3,4,5,6,7,8,9,10]
  2. Vazia e singular
    Código do teste
    main = print ((msort ([] :: [Int]), msort [4]))
    Esperado:
    ([],[4])
  3. Repetidos
    Código do teste
    main = print (msort [3,1,3,2,1])
    Esperado:
    [1,1,2,3,3]

Solução
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
  | x <= y = x : merge xs (y:ys)
  | otherwise = y : merge (x:xs) ys

msort :: Ord a => [a] -> [a]
msort [] = []
msort [x] = [x]
msort xs = merge (msort left) (msort right)
  where (left, right) = splitAt (length xs `div` 2) xs

As metades são menores para listas com pelo menos dois elementos. Depois de ordenadas, merge preserva todos os valores.

Voltar à explicação
Substituição em expressõesCódigo

Considere type Name = String; data Expr = Const Int | Var Name | Add Expr Expr | Mult Expr Expr; type Env = [(Name,Int)]. Defina recursivamente subst :: Env -> Expr -> Expr para substituir variáveis pelos valores do ambiente. Variáveis ausentes mantêm-se. Exemplos: subst [("x",2),("y",3)] (Add (Var "x") (Const 1)) = Add (Const 2) (Const 1); subst [("x",2),("y",3)] (Mult (Var "x") (Add (Var "y") (Const 1))) = Mult (Const 2) (Add (Const 3) (Const 1)); subst [("x",2),("y",3)] (Add (Var "x") (Var "z")) = Add (Const 2) (Var "z").

Haskell
type Name = String
data Expr = Const Int | Var Name | Add Expr Expr | Mult Expr Expr deriving (Eq, Show)
type Env = [(Name,Int)]
subst :: Env -> Expr -> Expr
subst = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Constante e variável
    Código do teste
    main = print (subst [("x",2),("y",3)] (Add (Var "x") (Const 1)))
    Esperado:
    Add (Const 2) (Const 1)
  2. Árvore aninhada
    Código do teste
    main = print (subst [("x",2),("y",3)] (Mult (Var "x") (Add (Var "y") (Const 1))))
    Esperado:
    Mult (Const 2) (Add (Const 3) (Const 1))
  3. Variável ausente
    Código do teste
    main = print (subst [("x",2),("y",3)] (Add (Var "x") (Var "z")))
    Esperado:
    Add (Const 2) (Var "z")
  4. Ambiente vazio
    Código do teste
    main = print (subst [] (Mult (Var "x") (Const 3)))
    Esperado:
    Mult (Var "x") (Const 3)

Solução
type Name = String
data Expr = Const Int | Var Name | Add Expr Expr | Mult Expr Expr deriving (Eq, Show)
type Env = [(Name,Int)]
subst :: Env -> Expr -> Expr
subst _ (Const n) = Const n
subst env (Var x) = maybe (Var x) Const (lookup x env)
subst env (Add a b) = Add (subst env a) (subst env b)
subst env (Mult a b) = Mult (subst env a) (subst env b)

lookup encontra o primeiro valor associado ao nome. A variável ausente é preservada; em cada operação percorrem-se ambos os ramos.

Voltar à explicação
Árvore binária para árvore rosaCódigo

Defina binary2rose :: BinaryTree a -> RoseTree a para converter data BinaryTree a = Leaf a | Node (BinaryTree a) a (BinaryTree a) em data RoseTree a = Rose a [RoseTree a]. Exemplo: binary2rose (Node (Node (Leaf 1) 2 (Leaf 3)) 4 (Node (Leaf 5) 6 (Leaf 7))) = Rose 4 [Rose 2 [Rose 1 [],Rose 3 []],Rose 6 [Rose 5 [],Rose 7 []]].

Haskell
data BinaryTree a = Leaf a | Node (BinaryTree a) a (BinaryTree a)
data RoseTree a = Rose a [RoseTree a] deriving (Eq, Show)
binary2rose :: BinaryTree a -> RoseTree a
binary2rose = undefined
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Folha
    Código do teste
    main = print (binary2rose (Leaf 1))
    Esperado:
    Rose 1 []
  2. Exemplo
    Código do teste
    main = print (binary2rose (Node (Node (Leaf 1) 2 (Leaf 3)) 4 (Node (Leaf 5) 6 (Leaf 7))))
    Esperado:
    Rose 4 [Rose 2 [Rose 1 [],Rose 3 []],Rose 6 [Rose 5 [],Rose 7 []]]
  3. Ramos distintos
    Código do teste
    main = print (binary2rose (Node (Leaf "e") "raiz" (Leaf "d")))
    Esperado:
    Rose "raiz" [Rose "e" [],Rose "d" []]

Solução
data BinaryTree a = Leaf a | Node (BinaryTree a) a (BinaryTree a)
data RoseTree a = Rose a [RoseTree a] deriving (Eq, Show)
binary2rose :: BinaryTree a -> RoseTree a
binary2rose (Leaf x) = Rose x []
binary2rose (Node l x r) = Rose x [binary2rose l, binary2rose r]

Uma folha não tem filhos. Um nó conserva o valor e converte recursivamente os filhos pela ordem esquerda, direita.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.