72
1/60 Programação Funcional Capítulo 6 Funções Recursivas José Romildo Malaquias Departamento de Computação Universidade Federal de Ouro Preto 2013.2

Capítulo 6 Funções Recursivas - DECOM-UFOP...3/60 Tópicos 1 Funções recursivas 2 Recursividade mútua 3 Recursividade de cauda 4 Recursividade sobre listas init e last elem length

  • Upload
    others

  • View
    9

  • Download
    0

Embed Size (px)

Citation preview

  • 1/60

    Programação Funcional

    Capítulo 6

    Funções Recursivas

    José Romildo Malaquias

    Departamento de ComputaçãoUniversidade Federal de Ouro Preto

    2013.2

  • 2/60

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 3/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 4/60

    Recursividade

    Recursividade é uma idéia inteligente que desempenha um papelcentral na programação funcional e na ciência da computação em geral.

    Recursividade é o mecanismo de programação no qual uma definiçãode função ou de outro objeto refere-se ao próprio objeto sendo definido.

    Assim função recursiva é uma função que é definida em termos de simesma.

    Recursividade é o mecanismo básico para repetições nas linguagensfuncionais.

    São sinônimos: recursividade, recursão, recorrência.

  • 5/60

    Estratégia recursiva

    Estratégia para a definição recursiva de uma função:1. dividir o problema em problemas menores do mesmo tipo2. resolver os problemas menores (dividindo-os em problemas ainda menores,

    se necessário)3. combinar as soluções dos problemas menores para formar a solução final

    Ao dividir o problema sucessivamente em problemas menoreseventualmente os casos simples são alcançados:

    não podem ser mais divididossuas soluções são definidas explicitamente

  • 6/60

    Definição recursiva

    De modo geral, uma definição de função recursiva é dividida em duaspartes:

    Há um ou mais casos base que dizem o que fazer emsituações simples, onde não é necessária nenhuma recursão.

    Nestes casos a resposta pode ser dada de imediato, sem chamarrecursivamente a função sendo definida.Isso garante que a recursão eventualmente pode parar.

    Há um ou mais casos recursivos que são mais gerais, e definem afunção em termos de uma chamada mais simples a si mesma.

  • 7/60

    Exemplo: fatorial

    A função que calcula o fatorial de um número natural pode ser definidarecursivamente como segue:fatorial :: Integer -> Integerfatorial n| n == 0 = 1| n > 0 = fatorial (n-1) * n

    A primeira equação estabelece que o fatorial de 0 é 1. Este é o casobase.A segunda equação estabelece que o fatorial de um número positivo é oproduto deste número e do fatorial do seu antecessor. Este é o casorecursivo.Observe que no caso recursivo o subproblema fatorial (n-1) é maissimples que o problema original fatorial n e está mais próximo docaso base fatorial 0 .

  • 8/60

    Exemplo: fatorial (cont.)

    Aplicando a função fatorial:fatorial 6{ fatorial 5 * 6{ (fatorial 4 * 5) * 6{ ((fatorial 3 * 4) * 5) * 6{ (((fatorial 2 * 3) * 4) * 5) * 6{ ((((fatorial 1 * 2) * 3) * 4) * 5) * 6{ (((((fatorial 0 * 1) * 2) * 3) * 4) * 5) * 6{ (((((1 * 1) * 2) * 3) * 4) * 5) * 6{ ((((1 * 2) * 3) * 4) * 5) * 6{ (((2 * 3) * 4) * 5) * 6{ ((6 * 4) * 5) * 6{ (24 * 5) * 6{ 120 * 6{ 720

  • 9/60

    Exemplo: fatorial (cont.)

    Exercício 1

    Digite a função fatorial em um arquivo fonte Haskell e carregue-o noambiente interativo de Haskell.a) Mostre que fatorial 7 = 5040.b) Determine o valor da expressão fatorial 7 usando o ambiente interativo.c) Determine o valor da expressão fatorial 1000 usando o ambiente

    interativo. Se você tiver uma calculadora científica, verifique o resultado nacalculadora.

    d) Qual é o valor esperado para a expressãodiv (fatorial 1000) (fatorial 999)? Determine o valor destaexpressão usando o ambiente interativo.

    e) O que acontece ao se calcular o valor da expressão fatorial (-2)?

  • 10/60

    Exemplo: potências de 2

    A função que calcula a potência de 2 (isto é, a base é 2) para númerosnaturais pode ser definida recursivamente como segue:potDois :: Integer -> IntegerpotDois n| n == 0 = 1| n > 0 = 2 * potDois (n-1)

    A primeira equação estabelece que 20 = 1. Este é o caso base.

    A segunda equação estabelece que 2n = 2 × 2n−1, sendo n > 0. Este é ocaso recursivo.

    Observe que no caso recursivo o subproblema potDois (n-1) é maissimples que o problema original potDois n e está mais próximo do casobase potDois 0 .

  • 11/60

    Exemplo: potências de 2 (cont.)

    Aplicando a função potência de 2:potDois 4{ 2 * potDois 3{ 2 * (2 * potDois 2){ 2 * (2 * (2 * potDois 1)){ 2 * (2 * (2 * (2 * potDois 0))){ 2 * (2 * (2 * (2 * 1))){ 2 * (2 * (2 * 2)){ 2 * (2 * 4){ 2 * 8{ 16

  • 12/60

    Exemplo: potências de 2 (cont.)

    Exercício 2

    Considere a seguinte definição para a função potência de 2:potDois’ :: Integer -> IntegerpotDois’ n| n == 0 = 1| otherwise = 2 * potDois’ (n-1)

    O que acontece ao calcular o valor da expressão potDois’ (-5)?

  • 13/60

    Exemplo: multiplicação

    A multiplicação de inteiros está disponível na biblioteca como umaoperação primitiva por questões de eficiência. Porém ela pode serdefinida usando recursividade em um de seus argumentos:mul :: Int -> Int -> Intmul m n| n == 0 = 0| n > 0 = m + mul m (n-1)| otherwise = negate (mul m (negate n))

    A primeira equação estabelece que quando o multiplicador é zero, oproduto também é zero. Este é o caso base.A segunda equação estabelece que m × n = m + m × (n − 1), sendon > 0. Este é um caso recursivo.A terceira equação estabelece que m × n = −(m × (−n)), sendo n < 0.Este é outro caso recursivo.

  • 14/60

    Exemplo: multiplicação (cont.)

    Aplicando a função multiplicação:mul 7 (-3){ negate (mul 7 (negate (-3))){ negate (mul 7 3){ negate (7 + mul 7 2){ negate (7 + (7 + mul 7 1)){ negate (7 + (7 + (7 + mul 7 0))){ negate (7 + (7 + (7 + 0))){ negate (7 + (7 + 7)){ negate (7 + 14){ negate 21{ -21

    A definição recursiva da multiplicação formalisa a idéia de que amultiplicação pode ser reduzida a adições repetidas.

  • 15/60

    Exemplo: multiplicação (cont.)

    Exercício 3

    Mostre que mul 5 6 = 30.

  • 16/60

    Exemplo: sequência de Fibonacci

    Na seqüência de Fibonacci

    0,1,1,2,3,5,8,13, . . .

    os dois primeiros elementos são 0 e 1, e cada elemento subseqüente édado pela soma dos dois elementos que o precedem na seqüência.A função a seguir calcula o n-ésimo número de Fibonnaci, para n ≥ 0:

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

    A primeira e segunda equações são os casos base.A terceira equação é o caso recursivo.

  • 17/60

    Exemplo: sequência de Fibonacci (cont.)

    Neste caso temos recursão múltipla, pois a função sendo definida éusada mais de uma vez em sua própria definição.

    Aplicando a função de fibonacci:fib 5{ fib 3 + fib 4{ (fib 1 + fib 2) + (fib 2 + fib 3){ (1 + (fib 0 + fib 1)) + ((fib 0 + fib 1) + (fib 1 + fib 2)){ (1 + (0 + 1)) + ((0 + 1) + (1 + (fib 0 + fib 1))){ (1 + 1) + (1 + (1 + (0 + 1))){ 2 + (1 + (1 + 1)){ 2 + (1 + 2){ 2 + 3{ 5

  • 18/60

    Exemplo: sequência de Fibonacci (cont.)

    Exercício 4

    Mostre que fib 6 = 8.

  • 19/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 20/60

    Recursividade mútua

    Recursividade mútua ocorre quando duas ou mais funções sãodefinidas em termos uma da outra.

  • 21/60

    Exemplo: par e ímpar

    As funções da biblioteca even (par) e odd (ímpar), que determinam seum número é par ou ímpar, respectivamente, geralmente são definidasusando o resto da divisão por dois:par, impar :: Int -> Bool

    par n = mod n 2 == 0

    impar n = not (par n)

  • 22/60

    Exemplo: par e ímpar (cont.)

    No entanto elas também podem ser definidas usando recursividademútua:par :: Int -> Boolpar n | n == 0 = True

    | n > 0 = impar (n-1)| otherwise = par (-n)

    impar :: Int -> Boolimpar n | n == 0 = False

    | n > 0 = par (n-1)| otherwise = impar (-n)

    Zero é par, mas não é ímpar.Um número positivo é par se seu antecessor é ímpar.Um número positivo é ímpar se seu antecessor é par.Um número negativo é par (ou ímpar) se o seu oposto for par (ou ímpar).

  • 23/60

    Exemplo: par e ímpar (cont.)

    Aplicando as função par e impar:par (-5){ par 5{ impar 4{ par 3{ impar 2{ par 1{ impar 0{ False

  • 24/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 25/60

    Recursividade de cauda

    Uma função recursiva apresenta recursividade de cauda se o resultadofinal da chamada recursiva é o resultado final da própria função.

    Se o resultado da chamada recursiva deve ser processado de algumamaneira para produzir o resultado final, então a função não apresentarecursividade de cauda.

  • 26/60

    Recursividade de cauda (cont.)

    Exemplo:A função recursiva a seguir não apresenta recursividade de cauda:

    fatorial :: Integer -> Integerfatorial n| n == 0 = 1| n > 0 = fatorial (n-1) * n

    No caso recursivo, o resultado da chamada recursiva fatorial (n-1) émultiplicado por n para produzir o resultado final.

  • 27/60

    Recursividade de cauda (cont.)

    Exemplo:A função recursiva a seguir não apresenta recursividade de cauda:

    par :: Integer -> Boolpar n| n == 0 = True| n > 0 = not (par (n-1))

    No caso recursivo, a função not é aplicada ao resultado da chamadarecursiva par (n-1) para produzir o resultado final.

  • 28/60

    Recursividade de cauda (cont.)

    Exemplo:A função recursiva potenciaDois’ a seguir apresenta recursividade decauda:potenciaDois :: Integer -> IntegerpotenciaDois n = potenciaDois’ n 1

    potenciaDois’ :: Integer -> Integer -> IntegerpotenciaDois’ n y| n == 0 = y| n > 0 = potenciaDois’ (n-1) (2*y)

    No caso recursivo, o resultado da chamada recursivapotenciaDois’ (n-1) (2*y) é o resultado final.

  • 29/60

    Recursividade de cauda (cont.)

    Exercício 5

    Mostre que potenciaDois 5 = 32.

    Exercício 6

    Faça uma definição recursiva da função par usando recursividade de cauda.

  • 30/60

    Otimização de chamada de cauda

    Em muitas implementações de linguagens de programação umachamada de função usa um espaço de memória (quadro, frame ouregistro de ativação) em uma área da memória (pilha ou stack) onde sãoarmazenadas informações importantes, como:

    argumentos da funçãovariáveis locaisvariáveis temporáriasendereço de retorno da função

  • 31/60

    Otimização de chamada de cauda (cont.)Uma chamada de cauda acontece quando uma função chama outrafunção como sua última ação, não tendo mais nada a fazer. O resultadofinal da função é dado pelo resultado da chamada de cauda.Em tais situações o programa não precisa voltar para a função quechama quando a função chamada termina.Portanto, após a chamada de cauda, o programa não precisa manterqualquer informação sobre a função chamadora na pilha.Algumas implementações de linguagem tiram proveito desse fato e naverdade não utilizam qualquer espaço extra de pilha quando fazem umachamada de cauda.Esta técnica é chamada de eliminação da cauda, otimização dechamada de cauda ou ainda otimização de chamada recursiva.A otimização de chamada de cauda permite que funções comrecursividade de cauda recorram indefinidamente sem estourar a pilha.Muitas linguagens funcionais não possuem estruturas de repetição eusam funções recursivas para fazer repetições.Nestes casos a otimização de chamada de cauda é fundamental parauma boa eficiência dos programas.

  • 32/60

    Vantagens de usar recursividade

    Muitas funções podem ser naturalmente definidas em termos de simesmas.Propriedades de funções definidas usando recursão podem ser provadasusando indução, uma técnica matemática simples, mas poderosa.

  • 33/60

    Exercícios

    Exercício 7

    O fatorial duplo de um número natural n é o produto de todos os números de1 (ou 2) até n, contados de 2 em 2. Por exemplo, o fatorial duplo de 8 é8 × 6 × 4 × 2 = 384, e o fatorial duplo de 7 é 7 × 5 × 3 × 1 = 105.Defina uma função para calcular o fatorial duplo usando recursividade.

    Exercício 8

    Defina uma função recursiva que recebe dois números naturais m e n eretorna o produto de todos os números no intervalo [m,n]:

    m × (m + 1) × · · · × (n − 1) × n

  • 34/60

    Exercícios (cont.)

    Exercício 9

    Usando a função definida no exercício 8, escreva uma definição nãorecursiva para calcular o fatorial de um número natural.

    Exercício 10

    Defina uma função recursiva para calcular a soma de dois números inteiros,sem usar os operadores + e -. Utilize as funções succ e pred da biblioteca,que calculam respectivamente o sucessor e o antecessor de um valor.

    Exercício 11

    Defina uma função recursiva para calcular a potência de um número,considerando que o expoente é um número natural. Utilize o método dasmultiplicações sucessivas.

  • 35/60

    Exercícios (cont.)

    Exercício 12

    A raiz quadrada inteira de um número inteiro positivo n é o maior númerointeiro cujo quadrado é menor ou igual a n. Por exemplo, a raiz quadradainteira de 15 é 3, e a raiz quadrada inteira de 16 é 4.Defina uma função recursiva para calcular a raiz quadrada inteira.

    Exercício 13

    Defina duas funções recursivas que calculam o quociente e o resto da divisãointeira de dois números inteiros usando subtrações sucessivas.

  • 36/60

    Exercícios (cont.)

    Exercício 14

    Defina uma função recursiva para calcular o máximo divisor comum de doisnúmeros inteiros não negativos a e b, usando o algoritmo de Euclides:

    mdc(a,b) =

    a se b = 0,mdc(b ,a mod b) se b > 0,mdc(a,−b) se b < 0

    Nota: o prelúdio já tem a função gcd :: Integral a => a -> a -> a quecalcula o máximo divisor comum de dois números inteiros.

  • 37/60

    Exercícios (cont.)

    Exercício 15

    Considere a seguinte função para calcular o fatorial de um número:fat n = fat’ n 1wherefat’ n x| n == 0 = x| n > 0 = fat’ (n-1) (n*x)

    a) Mostre que fat 6 = 720.b) Compare o cálculo de fat 6 com o cálculo de fatorial 6 apresentado

    anteriormente. Qual versão da função fatorial é mais eficiente: fatorialou fat? Explique.

    Exercício 16

    Defina uma função com recursividade de cauda para calcular o n-ésimo(n ≥ 0) número de Fibonacci.

  • 38/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 39/60

    Funções recursivas sobre listas

    Listas são estruturas recursivas:caso base: lista vazia[]

    caso recursivo: lista não vaziacabeca : cauda

    A maioria das operações com listas são definidas recursivamente:caso base: solução para a lista vaziacaso recursivo: solução para a lista não vazia

  • 40/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 41/60

    Operações com listas: init

    init seleciona todos os elementos de uma lista não vazia, exceto oúltimo elemento.Exemplos:

    init [15] { []init [True,False] { [True]init [1,2,3,4,5] { [1,2,3,4]init "Brasil" { "Brasi"init [] { erro

    Definição:init :: [a] -> [a]

    init [_] = []init (x:xs) = x : init xs

  • 41/60

    Operações com listas: init

    init seleciona todos os elementos de uma lista não vazia, exceto oúltimo elemento.Exemplos:

    init [15] { []init [True,False] { [True]init [1,2,3,4,5] { [1,2,3,4]init "Brasil" { "Brasi"init [] { erro

    Definição:init :: [a] -> [a]

    init [_] = []init (x:xs) = x : init xs

  • 42/60

    Operações com listas: last

    last seleciona o último elemento de uma lista não vazia.Exemplos:last [15] { 15last [True,False] { Falselast [1,2,3,4,5] { 5last "Brasil" { ’l’last [] { erro

    Definição:last :: [a] -> a

    last [x] = xlast (_:xs) = last xs

  • 42/60

    Operações com listas: last

    last seleciona o último elemento de uma lista não vazia.Exemplos:last [15] { 15last [True,False] { Falselast [1,2,3,4,5] { 5last "Brasil" { ’l’last [] { erro

    Definição:last :: [a] -> a

    last [x] = xlast (_:xs) = last xs

  • 43/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 44/60

    Operações com listas: elem

    elem recebe um valor e uma lista e retorna True se e somente se o valoré um elemento da lista.Exemplos:

    elem 5 [] { Falseelem 5 [5] { Trueelem 5 [4,5] { Trueelem ’d’ "Pedro" { True8 ‘elem‘ [2,4,6,8,10] { True’#’ ‘elem‘ "Pedro" { False

    Definição:

    infixl 4 ‘elem‘

    elem :: Eq a => a -> [a] -> Bool

    elem _ [] = Falseelem x (y:ys) = x == y || elem x ys

  • 44/60

    Operações com listas: elem

    elem recebe um valor e uma lista e retorna True se e somente se o valoré um elemento da lista.Exemplos:

    elem 5 [] { Falseelem 5 [5] { Trueelem 5 [4,5] { Trueelem ’d’ "Pedro" { True8 ‘elem‘ [2,4,6,8,10] { True’#’ ‘elem‘ "Pedro" { False

    Definição:

    infixl 4 ‘elem‘

    elem :: Eq a => a -> [a] -> Bool

    elem _ [] = Falseelem x (y:ys) = x == y || elem x ys

  • 45/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 46/60

    Operações com listas: length

    length retorna o número de elementos de uma lista finita.Exemplos:

    length [] { 0length [15] { 1length [div 2 0, mod 3 0] { 2length [1,2,3,4,5] { 5length "Brasil" { 6

    Definição:length :: [a] -> Int

    length [] = 0length (_:xs) = 1 + length xs

  • 46/60

    Operações com listas: length

    length retorna o número de elementos de uma lista finita.Exemplos:

    length [] { 0length [15] { 1length [div 2 0, mod 3 0] { 2length [1,2,3,4,5] { 5length "Brasil" { 6

    Definição:length :: [a] -> Int

    length [] = 0length (_:xs) = 1 + length xs

  • 47/60

    Operações com listas: (!!)

    (!!) recebe uma lista e um número inteiro e retorna o elemento da listacuja posição é dada pelo número.A posição do primeiro elemento é zero.A posição do último elemento é o tamanho da lista menos um.Se a posição for inválida ocorre um erro.Exemplos:[1,2,3,4,5] !! 0 { 1[1,2,3,4,5] !! 1 { 2"Brasil" !! 3 { ’s’[35,46] !! 8 { erro[35,46] !! (-2) { erro

    Definição

    infixl 9 !!

    (!!) :: [a] -> Int -> a

    (x:_) !! 0 = x(_:xs) !! n = xs !! (n-1)

  • 47/60

    Operações com listas: (!!)

    (!!) recebe uma lista e um número inteiro e retorna o elemento da listacuja posição é dada pelo número.A posição do primeiro elemento é zero.A posição do último elemento é o tamanho da lista menos um.Se a posição for inválida ocorre um erro.Exemplos:[1,2,3,4,5] !! 0 { 1[1,2,3,4,5] !! 1 { 2"Brasil" !! 3 { ’s’[35,46] !! 8 { erro[35,46] !! (-2) { erro

    Definição

    infixl 9 !!

    (!!) :: [a] -> Int -> a

    (x:_) !! 0 = x(_:xs) !! n = xs !! (n-1)

  • 48/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 49/60

    Operações com listas: take

    take recebe um número inteiro n e uma lista xs e retorna o prefixo detamanho n da lista xs.Exemplos:take 5 "Hello World!" { "Hello"take 3 [1,2,3,4,5] { [1,2,3]take 3 [1,2] { [1,2]take 3 [] { []take (-9) [1,2] { []take 0 [1,2] { []

    Definiçãotake :: Int -> [a] -> [a]

    take n _ | n

  • 49/60

    Operações com listas: take

    take recebe um número inteiro n e uma lista xs e retorna o prefixo detamanho n da lista xs.Exemplos:take 5 "Hello World!" { "Hello"take 3 [1,2,3,4,5] { [1,2,3]take 3 [1,2] { [1,2]take 3 [] { []take (-9) [1,2] { []take 0 [1,2] { []

    Definiçãotake :: Int -> [a] -> [a]

    take n _ | n

  • 50/60

    Operações com listas: drop

    drop recebe um número inteiro n e uma lista xs e retorna o sufixo da listaxs após os n primeiros elementos.Exemplos:drop 6 "Hello World!" { "World!"drop 3 [1,2,3,4,5] { [4,5]drop 3 [1,2] { []drop 3 [] { []drop (-9) [1,2] { [1,2]drop 0 [1,2] { [1,2]

    Definiçãodrop :: Int -> [a] -> [a]

    drop n xs | n

  • 50/60

    Operações com listas: drop

    drop recebe um número inteiro n e uma lista xs e retorna o sufixo da listaxs após os n primeiros elementos.Exemplos:drop 6 "Hello World!" { "World!"drop 3 [1,2,3,4,5] { [4,5]drop 3 [1,2] { []drop 3 [] { []drop (-9) [1,2] { [1,2]drop 0 [1,2] { [1,2]

    Definiçãodrop :: Int -> [a] -> [a]

    drop n xs | n

  • 51/60

    Operações com listas: splitAt

    splitAt recebe um número inteiro n e uma lista xs e retorna um paronde o primeiro elemento é um prefixo de tamanho n de xs e o segundoelemento é o resto da lista.Exemplos:splitAt 6 "Hello World!" { ("Hello ","World!")splitAt 3 [1,2,3,4,5] { ([1,2,3],[4,5])splitAt 1 [1,2,3] { ([1],[2,3])splitAt 3 [1,2,3] { ([1,2,3],[])splitAt 4 [1,2,3] { ([1,2,3],[])splitAt 0 [1,2,3] { ([],[1,2,3])splitAt (-9) [1,2,3] { ([],[1,2,3])

    DefiniçãosplitAt :: Int -> [a] -> ([a],[a])

    splitAt n xs | n

  • 51/60

    Operações com listas: splitAt

    splitAt recebe um número inteiro n e uma lista xs e retorna um paronde o primeiro elemento é um prefixo de tamanho n de xs e o segundoelemento é o resto da lista.Exemplos:splitAt 6 "Hello World!" { ("Hello ","World!")splitAt 3 [1,2,3,4,5] { ([1,2,3],[4,5])splitAt 1 [1,2,3] { ([1],[2,3])splitAt 3 [1,2,3] { ([1,2,3],[])splitAt 4 [1,2,3] { ([1,2,3],[])splitAt 0 [1,2,3] { ([],[1,2,3])splitAt (-9) [1,2,3] { ([],[1,2,3])

    DefiniçãosplitAt :: Int -> [a] -> ([a],[a])

    splitAt n xs | n

  • 52/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 53/60

    Operações com listas: (++)

    (++) concatena duas listas.Exemplos:

    [] ++ [20,10] { [20,10][4] ++ [20,10] { [4,20,10][1,2,3,4,5] ++ [20,10] { [1,2,3,4,5,20,10]"ana" ++ " carolina" { "ana carolina"[(10,True),(5,False)] ++ [] { [(10,True),(5,False)][1,2] ++ [] ++ [1] ++ [0,3] { [1,2,1,0,3]

    Definição

    infixr 5 ++

    (++) :: [a] -> [a] -> [a]

    [] ++ ys = ys(x:xs) ++ ys = x : (xs ++ ys)

  • 53/60

    Operações com listas: (++)

    (++) concatena duas listas.Exemplos:

    [] ++ [20,10] { [20,10][4] ++ [20,10] { [4,20,10][1,2,3,4,5] ++ [20,10] { [1,2,3,4,5,20,10]"ana" ++ " carolina" { "ana carolina"[(10,True),(5,False)] ++ [] { [(10,True),(5,False)][1,2] ++ [] ++ [1] ++ [0,3] { [1,2,1,0,3]

    Definição

    infixr 5 ++

    (++) :: [a] -> [a] -> [a]

    [] ++ ys = ys(x:xs) ++ ys = x : (xs ++ ys)

  • 54/60

    Operações com listas: concat

    concat aplicada a uma lista de listas, concatena as listas em uma únicalistaExemplos:

    concat [] { []concat [[1,2,3]] { [1,2,3]concat [[1,2,3], [4]] { [1,2,3,4]concat [[1,2,3], [4], [], [5,6,7,8]] { [1,2,3,4,5,6,7,8]concat ["we"," ","like"," ","lists"] { "we like lists"

    Definiçãoconcat :: [[a]] -> [a]

    concat [] = []concat (xs:xss) = xs ++ concat xss

  • 54/60

    Operações com listas: concat

    concat aplicada a uma lista de listas, concatena as listas em uma únicalistaExemplos:

    concat [] { []concat [[1,2,3]] { [1,2,3]concat [[1,2,3], [4]] { [1,2,3,4]concat [[1,2,3], [4], [], [5,6,7,8]] { [1,2,3,4,5,6,7,8]concat ["we"," ","like"," ","lists"] { "we like lists"

    Definiçãoconcat :: [[a]] -> [a]

    concat [] = []concat (xs:xss) = xs ++ concat xss

  • 55/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 56/60

    Operações com listas: reverse

    reverse recebe uma lista finita e retorna uma lista com os mesmoselementos, porém em ordem reversa.Exemplos:

    reverse [] { []reverse [1] { [1]reverse [1,2] { [2,1]reverse [1,2,3] { [3,2,1]reverse [1,2,3,4,5] { [5,4,3,2,1]reverse "ROMA" { "AMOR"

    Definiçãoreverse :: [a] -> [a]

    reverse [] = []reverse (x:xs) = reverse xs ++ [x]

  • 56/60

    Operações com listas: reverse

    reverse recebe uma lista finita e retorna uma lista com os mesmoselementos, porém em ordem reversa.Exemplos:

    reverse [] { []reverse [1] { [1]reverse [1,2] { [2,1]reverse [1,2,3] { [3,2,1]reverse [1,2,3,4,5] { [5,4,3,2,1]reverse "ROMA" { "AMOR"

    Definiçãoreverse :: [a] -> [a]

    reverse [] = []reverse (x:xs) = reverse xs ++ [x]

  • 57/60

    Tópicos

    1 Funções recursivas

    2 Recursividade mútua

    3 Recursividade de cauda

    4 Recursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip

  • 58/60

    Operações com listas: zip

    zip recebe duas listas e retorna a lista dos pares formados peloselementos correspondentes da primeira e da segunda lista.Se as listas forem de tamanhos diferentes, o tamanho do resultado é omenor tamanho.Exemplos:

    zip [] [] { []zip [1,2,3] [] { []zip [] [1,2,3] { []zip [True] [1] { [(True,1)]zip [1,2] ["ana","pedro"] { [(1,"ana"),(2,"pedro")]zip [1,2,3] "ABC" { [(1,’A’),(2,’B’),(3,’C’)]zip [1,2,3,4,5] [0.5,0.6] { [(1,0.5),(2,0.6)]zip [1,2,3] "BRASIL" { [(1,’B’),(2,’R’),(3,’A’)]

    Definiçãozip :: [a] -> [b] -> [(a, b)]

    zip (x:xs) (y:ys) = (x,y) : zip xs yszip _ _ = []

  • 58/60

    Operações com listas: zip

    zip recebe duas listas e retorna a lista dos pares formados peloselementos correspondentes da primeira e da segunda lista.Se as listas forem de tamanhos diferentes, o tamanho do resultado é omenor tamanho.Exemplos:

    zip [] [] { []zip [1,2,3] [] { []zip [] [1,2,3] { []zip [True] [1] { [(True,1)]zip [1,2] ["ana","pedro"] { [(1,"ana"),(2,"pedro")]zip [1,2,3] "ABC" { [(1,’A’),(2,’B’),(3,’C’)]zip [1,2,3,4,5] [0.5,0.6] { [(1,0.5),(2,0.6)]zip [1,2,3] "BRASIL" { [(1,’B’),(2,’R’),(3,’A’)]

    Definiçãozip :: [a] -> [b] -> [(a, b)]

    zip (x:xs) (y:ys) = (x,y) : zip xs yszip _ _ = []

  • 59/60

    Exercícios

    Exercício 17

    Defina a função recursivaproduct :: Num a => [a] -> aque retorna o produto de uma lista de números.

    Exercício 18

    Defina as funções recursivasand :: [Bool] -> Boolor :: [Bool] -> Boolque retornam respectivamente a conjunção e a disjunção de uma lista devalores lógicos.

  • 60/60

    Fim

    Funções recursivasRecursividade mútuaRecursividade de caudaRecursividade sobre listasinit e lastelemlength e (!!)take, drop e splitAt(++) e concatreversezip