Programação Funcional

50 Questões Fichas Testes/Exames

Ficha 4: Otimização com tupling e acumuladores. Listas por compreensão.

Voltar

1) Defina a função digitAlpha :: String -> (String,String) que, dada uma string, devolve um par de strings: uma apenas com as letras presentes nessa string, e a outra apenas com os números presentes na string. Implemente a função de modo a fazer uma única travessia da string. Relembre que as funções isDigit, isAlpha :: Char -> Bool estão já definidas no módulo Data.Char.

digitAlpha :: String -> (String,String)
digitAlpha "" = ("","")
digitAlpha (h:t)
    | isAlpha h = (  digits, h:letters)
    | isDigit h = (h:digits,   letters)
    | otherwise = (  digits,   letters)
    where (digits, letters) = digitAlpha t

2) Defina a função nzp :: [Int] -> (Int,Int,Int) que, dada uma lista de inteiros, conta o número de valores negativos, o número de zeros e o número de valores positivos, devolvendo um triplo com essa informação. Certifique-se que a função que definiu percorre a lista apenas uma vez.

nzp :: [Int] -> (Int,Int,Int)
nzp [] = (0,0,0)
nzp (h:t)
    | h < 0 = (n + 1, z, p)
    | h == 0 = (n, z + 1, p)
    | otherwise = (n, z, p + 1)
    where (n, z, p) = nzp t

3) Defina a função divMod :: Integral a => a -> a -> (a, a) que calcula simultaneamente a divisão e o resto da divisão inteira por subtrações sucessivas.

divMod :: Integral a => a -> a -> (a, a)
divMod x y
    | x - y < 0 = (0,x)
    | otherwise = (q+1,r)
    where (q,r) = divMod (x - y) y

-- a versão acima funciona apenas para números positivos
-- a versão abaixo funciona para quaisquer valores inteiros

divMod' :: Integral a => a -> a -> (a, a)
divMod' x y 
    | x < 0 = let (q,r) = divMod' (-x) y in (if r == 0 then (-q,r) else (-q-1,-r+y))
    | y < 0 = let (q,r) = divMod' (-x) (-y) in (q,-r)
    | otherwise = if x - y < 0 then (0,x) else (let (q,r) = divMod' (x - y) y in (q+1,r))

4) Utilizando uma função auxiliar com um acumulador, otimize a seguinte definição recursiva que determina qual o número que corresponde a uma lista de digitos.

fromDigits :: [Int] -> Int
fromDigits [] = 0
fromDigits (h:t) = h*10^(length t) + fromDigits t

Note que

    fromDigits [1,2,3,4] = 1 * 10^3 + 2 * 10^2 + 3 * 10^1 + 4 * 10^0 
                         = 4 + 10 (3 + 10 (2 + 10 (1 + 10 * 0)))
fromDigits :: [Int] -> Int
fromDigits l = fromDigitsAux l 0

fromDigitsAux :: [Int] -> Int -> Int
fromDigitsAux [] acc = acc
fromDigitsAux (h:t) acc = fromDigitsAux t (h + 10 * acc)

5) Utilizando uma função auxiliar com acumuladores, otimize a seguinte definição que determina a soma do segmento inicial de uma lista com soma máxima.

maxSumInit :: (Num a, Ord a) => [a] -> a
maxSumInit l = maximum [sum m | m <- inits l]
maxSumInit :: (Num a, Ord a) => [a] -> a
maxSumInit l = maxSumInitAux l (sum l)

maxSumInitAux :: (Num a, Ord a) => [a] -> a -> a
maxSumInitAux [] acc = acc
maxSumInitAux l acc = if si > acc then maxSumInitAux il si else maxSumInitAux il acc
    where il = init l
          si = sum il

6) Otimize a seguinte definição recursiva da função que calcula o n-ésimo número da sequência de Fibonacci, usando uma função auxiliar com 2 acumuladores que representam, respectivamente, o n-ésimo e o n+1-ésimo números dessa sequência.

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fibAux (n-2) 0 1

fibAux :: Int -> Int -> Int -> Int
fibAux 0 n _ = n
fibAux i fib_n fib_n_mais_1 = fibAux (i - 1) fib_n_plus_1 (fib_n + fib_n_plus_1)

7) Defina a função intToStr :: Integer -> String que converte um inteiro numa string. Utilize uma função auxiliar com um acumulador onde vai construindo a string que vai devolver no final.

intToStr :: Integer -> String
intToStr 0 = "zero"
intToStr n = intToStrAux n ""

intToStrAux :: Integer -> String -> String
intToStrAux 0 ('-':acc) = acc
intToStrAux n acc = intToStrAux nn ((case r of 
        0 -> "-zero"
        1 -> "-um"
        2 -> "-dois"
        3 -> "-três"
        4 -> "-quatro"
        5 -> "-cinco"
        6 -> "-seis"
        7 -> "-sete"
        8 -> "-oito"
        9 -> "-nove") ++ acc)
    where (nn,r) = n `divMod` 10

8) Para cada uma das expressões seguintes, exprima por enumeração a lista correspondente. Tente ainda, para cada caso, descobrir uma outra forma de obter o mesmo resultado.

a) [x | x <- [1..20], mod x 2 == 0, mod x 3 == 0]

[6,12,18]

[x | x <- [1..20], mod x 6 == 0]

b) [x | x <- [y | y <- [1..20], mod y 2 == 0], mod x 3 == 0]

[6,12,18]

[x | x <- [1..20], mod x 6 == 0]

c) [(x,y) | x <- [0..20], y <- [0..20], x+y == 30]

[(10,20),(11,19),(12,18),(13,17),(14,16),(15,15),(16,14),(17,13),(18,12),(19,11),(20,10)]

[(x, 30 - x) | x <- [10..20]]

d) [sum [y | y <- [1..x], odd y] | x <- [1..10]]

[1,1,4,4,9,9,16,16,25,25]

[ x^2 | x <- [1..5], y <- [1..2]]

9) Defina cada uma das listas seguintes por compreensão.

a) [1,2,4,8,16,32,64,128,256,512,1024]

[ 2^x | x <- [0..10]]

b) [(1,5),(2,4),(3,3),(4,2),(5,1)]

[(x,y) | x <- [1..5], y <- [1..5], x + y == 6]

c) [[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]

[[1..x] | x <- [1..5]]

d) [[1],[1,1],[1,1,1],[1,1,1,1],[1,1,1,1,1]]

[ replicate x 1 | x <- [1..5]]

e) [1,2,6,24,120,720]

[ product [y | y <- [1..x]] | x <- [1..6]]