Programação Funcional

50 Questões Fichas Testes/Exames

Teste 2022-01-12

Voltar

1. Apresente uma definição recursiva da função (pré-definida) zip :: [a] -> [b] -> [(a,b)] que constrói uma lista de pares a partir de duas listas. Por exemplo, zip [1,2,3] [10,20,30,40] corresponde a [(1,10),(2,20),(3,30)].

zip :: [a] -> [b] -> [(a,b)]
zip [] _ = []
zip _ [] = []
zip (h:t) (h':t') = (h,h') : zip t t'

2. Defina a função preCrescente :: Ord a => [a] -> [a] que calcula o maior prefixo crescente de uma lista. Por exemplo, preCrescente [3,7,9,6,10,22] corresponde a [3,7,9] e preCrescente [1,2,7,9,9,1,8] corresponde a [1,2,7,9].

preCrescente :: Ord a => [a] -> [a]
preCrescente [] = []
preCrescente [x] = [x]
preCrescente (h:s:t)
    | s >= h = h : preCrescente (s:t)
    | otherwise = [h]

3. A amplitude de uma lista de inteiros define-se como a diferença entre o maior e o menor dos elementos da lista (a amplitude de uma lista vazia é 0). Defina a função amplitude :: [Int] -> Int que calcula a amplitude de uma lista (idealmente numa única passagem pela lista).

amplitude :: [Int] -> Int
amplitude l = uncurry (flip (-)) . foldr (\x (acc_min,acc_max) -> (min x acc_min, max x acc_max)) (head l, head l) $ l

4. Considere o seguinte tipo type Mat a = [[a]] para representar matrizes. Defina a função soma :: Num a => Mat a -> Mat a -> Mat a que soma duas matrizes da mesma dimensão.

soma :: Num a => Mat a -> Mat a -> Mat a
soma = zipWith . zipWith $ (+)

5. Decidiu-se organizar uma agenda telefónica numa árvore binária de procura (ordenada por ordem alfabética de nomes). Para isso, declararam-se os seguintes tipos de dados:

type Nome = String
type Telefone = Integer
data Agenda = Vazia | Nodo (Nome, [Telefone]) Agenda Agenda

Defina Agenda como instância da classe Show de forma a que a visualização da árvore resulte numa listagem da informação ordenada por ordem alfabética (com um registo por linha) e em que os vários telefones associados a um nome se apresentem separados por /.

import Data.List (intercalate)

instance Show Agenda where
    show Vazia = ""
    show (Nodo (nome, tlfs) l r) = 
        show l
        ++ nome ++ " " ++ intercalate "/" (map show tlfs) ++ "\n"
        ++ show r

6. Defina uma função randomSel :: Int -> [a] -> IO [a] que dado um inteiro n e uma lista l, produz uma lista com n elementos seleccionados aleatoriamente de l. Um elemento não pode aparecer na lista produzida mais vezes do que aparece na lista argumento. Se n for maior do que o comprimento da lista a função deverá retornar uma permutação da lista argumento. Por exemplo, a invocação de randomSel 3 [1,3,1,4,2,8,9,5] poderia produzir qualquer uma das listas [1,4,2], [5,2,8] ou [1,9,1], mas nunca [2,3,2].

randomSel :: Show a => Int -> [a] -> IO [a]
randomSel _ [] = return []
randomSel 0 _ = return []
randomSel n l = 
    randomRIO (1, length l)
    >>= (\randomN -> 
        fmap (l !! (randomN - 1) :) (randomSel (n - 1) (take (randomN - 1) l ++ drop randomN l))
    )

7. Defina uma função organiza :: Eq a => [a] -> [(a, [Int])] que, dada uma lista constrói uma lista em que, para cada elemento da lista original se guarda a lista dos índices onde esse elemento ocorre. Por exemplo, organiza "abracadabra" corresponde a [('a',[0,3,5,7,10]), ('b',[1,8]), ('r',[2,9]), ('c',[4]), ('d',[6])].

organiza :: Eq a => [a] -> [(a,[Int])]
organiza = foldr (\a -> insere a . map (\(c,is) -> (c,map (+1) is))) []

insere :: Eq a => a -> [(a,[Int])] -> [(a,[Int])]
insere x [] = [(x,[0])]
insere x ((c,is):t)
    | x == c = (c, 0 : is) : t
    | otherwise = (c,is) : insere x t

8. Apresente uma definição alternativa da função func, usando recursividade explícita em vez de funções de ordem superior e fazendo uma única travessia da lista.

func :: [[Int]] -> [Int]
func 1 = concat (filter (x -> sum x >10) 1)
func :: [[Int]] -> [Int]
func [] = []
func (h:t)
    | sum h > 10 = h ++ func t
    | otherwise = func t

9. Considere a seguinte estrutura para manter um dicionário, onde as palavras estão organizadas de forma alfabética.

data RTree a = R a [RTree a]
type Dictionary = [ RTree (Char, Maybe String) ]

d1 = [R ('c',Nothing) [
        R ('a',Nothing) [
            R ('r', Nothing) [
                R ('a',Just "...") [
                    R ('s', Just "...") [] ],
                R ('o',Just "...") [],
                R ('r',Nothing) [
                    R ('o',Just "...") [] ]
     ]  ]   ]   ]

Cada árvore agrupa todas as palavras começadas numa dada letra. As palavras constroem-se descendo na árvore a partir da raiz. Quando uma palavra está completa, o valor associado à última letra é Just s, sendo s uma string com a descrição da palavra em causa (que corresponde ao caminho desde a raiz até aí). Caso contrário é Nothing.

Por exemplo, d1 é um dicionário com as palavras: cara, caras, caro e carro.

Defina a função insere :: String -> String -> Dictionary -> Dictionary que, dadas uma palavra e a informação a ela associada, acrescenta essa entrada no dicionário. Se a palavra já existir no dicionário, atualiza a informação a ela associada.

insere :: String -> String -> Dictionary -> Dictionary
insere [x] desc dict = insereFim x desc dict
insere (h:t) desc [] = [ R (h,Nothing) (insere t desc [])]
insere (h:t) desc (R (a,b) l:d)
    | h == a = R (a,b) (insere t desc l) : d
    | otherwise = R (a,b) l : insere (h:t) desc d

insereFim :: Char -> String -> Dictionary -> Dictionary
insereFim x desc [] = [ R (x,Just desc) [] ]
insereFim x desc (R (a,b) l:t) 
    | x == a = R (a,Just desc) l : t
    | otherwise = R (a,b) l : insereFim x desc t