Acumuladores. Paradigma de Programação Funcional. Marco A L Barbosa



Documentos relacionados
Organização e Arquitetura de Computadores I

Algoritmos de Busca em Tabelas

O modelo do computador

Dados compostos. Paradigma de Programação Lógico. Marco A L Barbosa

Introdução à Programação. Recursão

Excel Planilhas Eletrônicas

Naturais. Paradigma de Programação Funcional. Marco A L Barbosa

Introdução. Introdução. Introdução. Organização Estruturada de Computadores. Introdução. Máquinas Multiníveis

Arquitetura de Rede de Computadores


ARQUITETURA E ORGANIZAÇÃO DE COMPUTADORES SISTEMAS DE NUMERAÇÃO: REPRESENTAÇÃO EM PONTO FLUTUANTE. Prof. Dr. Daniel Caetano

Departamento de Matemática - UEL Ulysses Sodré. Arquivo: minimaxi.tex - Londrina-PR, 29 de Junho de 2010.

INTRODUÇÃO ÀS LINGUAGENS DE PROGRAMAÇÃO

Dadas a base e a altura de um triangulo, determinar sua área.

x0 = 1 x n = 3x n 1 x k x k 1 Quantas são as sequências com n letras, cada uma igual a a, b ou c, de modo que não há duas letras a seguidas?

REVISÃO E AVALIAÇÃO DA MATEMÁTICA

Introdução à Arquitetura de Computadores. Renan Manola Introdução ao Computador 2010/01

Informática I. Aula 5. Aula 5-13/05/2006 1

Orientação a Objetos

UNIVERSIDADE FEDERAL DO PARANÁ UFPR Bacharelado em Ciência da Computação

CAP. I ERROS EM CÁLCULO NUMÉRICO

Matemática Financeira II

Na medida em que se cria um produto, o sistema de software, que será usado e mantido, nos aproximamos da engenharia.

DICAS PARA CÁLCULOS MAIS RÁPIDOS ARTIGO 07

E A D - S I S T E M A S L I N E A R E S INTRODUÇÃO

1. Introdução ao uso da calculadora

6.3 Equivalência entre Autômatos com Pilha Não-Determinísticos e Gramáticas Livre do Contexto

ESTRUTURA DE DADOS PILHA

1.1. Organização de um Sistema Computacional

Notas de Cálculo Numérico

Gestão da Qualidade Políticas. Elementos chaves da Qualidade 19/04/2009

Entendendo como funciona o NAT

Estrutura de Dados Básica

Pedro e Lucas estão sendo tratados com. Profilaxia

Compiladores - Análise Preditiva

Unidade 5: Sistemas de Representação

EA773 - Experimento 5

Autómatos Finitos Determinísticos

Utilização do SOLVER do EXCEL

APLICAÇÃO REDE APLICAÇÃO APRESENTAÇÃO SESSÃO TRANSPORTE REDE LINK DE DADOS FÍSICA 1/5 PROTOCOLOS DE REDE

BUSCA EM LISTAS LISTAS SEQÜENCIAIS, LISTAS SIMPLESMENTE E DUPLAMENTE ENCADEADAS E LISTAS CIRCULARES

CAPÍTULO 3 - TIPOS DE DADOS E IDENTIFICADORES

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS

Protocolo TCP/IP. Neste caso cada computador da rede precisa de, pelo menos, dois parâmetros configurados:

Componentes do Computador e. aula 3. Profa. Débora Matos

Só Matemática O seu portal matemático FUNÇÕES

Analise o código abaixo:

2. Representação Numérica

Profª Adriana Ferrazza 1. Fonte: BMF&Bovespa. 1. Juro simples. FV= PV.[1+(i.n)]

Estabilizada de. PdP. Autor: Luís Fernando Patsko Nível: Intermediário Criação: 22/02/2006 Última versão: 18/12/2006

a 1 x a n x n = b,

Exemplo de Subtração Binária

Estruturas de controle no nível de sentença

Aplicação Prática de Lua para Web

Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO)

CAPÍTULO 6 ARITMÉTICA DIGITAL

Combinação de modelos

Resolução de problemas e desenvolvimento de algoritmos

Sistemas Operacionais

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

Linguagem de Programação II

Métodos de Pesquisa em Memória Primária

Introdução às Linguagens de Programação

Podemos encontrar uma figura interessante no PMBOK (Capítulo 7) sobre a necessidade de organizarmos o fluxo de caixa em um projeto.

3 Sistemas de Numeração:

UM CONCEITO FUNDAMENTAL: PATRIMÔNIO LÍQUIDO FINANCEIRO. Prof. Alvaro Guimarães de Oliveira Rio, 07/09/2014.

Nos capítulos anteriores considerámos alguns aspectos da programação, estudámos

por séries de potências

Organização e Arquitetura de Computadores I

Gerenciamento de Problemas

Função. Definição formal: Considere dois conjuntos: o conjunto X com elementos x e o conjunto Y com elementos y. Isto é:

Esta dissertação apresentou duas abordagens para integração entre a linguagem Lua e o Common Language Runtime. O objetivo principal da integração foi

ARRAYS. Um array é um OBJETO que referencia (aponta) mais de um objeto ou armazena mais de um dado primitivo.

Teoria Princípio do Capacitor

SEQÜÊNCIA DE PULSO. Spin-eco (SE); Inversion-recovery (IR); Gradiente-eco (GRE); Imagens eco - planares (EPI).

Programação Funcional. Capítulo 1. Introdução. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2015.

Módulo 4. Construindo uma solução OLAP

Conteúdo. Disciplina: INF Engenharia de Software. Monalessa Perini Barcellos. Centro Tecnológico. Universidade Federal do Espírito Santo

Programação WEB I Estruturas de controle e repetição

Organização de Computadores Software

Os capacitores são componentes largamente empregados nos circuitos eletrônicos. Eles podem cumprir funções tais como o armazenamento de cargas

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008

1.6. Tratamento de Exceções

Trabalho 2 Fundamentos de computação Gráfica

A Torre de Hanói e o Princípio da Indução Matemática

Matemática Financeira II

Fim do fator previdenciário para quem atingir a. fórmula 95 para homens e 85 para mulheres.

PROGRAMAÇÃO EM LINGUAGEM LADDER LINGUAGEM DE RELÉS

Nova Versão 3.0 do Software de Gestão de Equipamentos da Katun KDFM!

Figure 2 - Nós folhas de uma árvore binária representando caracteres ASCII

PAYBACK - CALCULANDO O TEMPO NECESSÁRIO PARA RECUPERAR O INVESTIMENTO

Programador/a de Informática

APOSTILA DE INTEGRAÇÃO CONTROLLER

PARA CASA * Como voce faria para armazenar o resultado em uma variavel chamada NOME?

9. Derivadas de ordem superior

OPERADORES E ESTRUTURAS DE CONTROLE

Matemática Financeira Módulo 2

Transcrição:

Acumuladores Paradigma de Programação Funcional Marco A L Barbosa cba Este trabalho está licenciado com uma Licença Creative Commons - Atribuição-CompartilhaIgual 4.0 Internacional. http://github.com/malbarbo/na-func

Conteúdo Falta de contexto na recursão Processos iterativos e recursivos Recursão em cauda Projetando funções com acumuladores Função foldl foldr vs foldl

Falta de contexto na recursão

Falta de contexto na recursão Não nos preocupamos com o contexto do uso quando criamos funções recursivas Não importa se é a primeira vez que a função está sendo chamada ou se é a 100 Este princípio de independência do contexto facilita a escrita de funções recursivas, mas pode gerar problemas em alguns situações 4 / 30

Falta de contexto na recursão Dado uma lista de distâncias relativas entre pontos (começando da origem) em uma linha, defina uma função que calcule a distância absoluta a partir da origem ;; Lista(Número) -> Lista(Número) ;; Converte uma lista de dist^ancias relativas para uma lista de ;; dist^ancias absolutas. O primeito item da lista representa a ;; dist^ancia da origem. (define relativa->absoluta-tests (test-suite "relativa->absoluta tests" (check-equal? (relativa->absoluta (list 50 40 70 30 30)) (list 50 90 160 190 220)))) (define (relativa->absoluta lst) (define (somador n) (λ (x) (+ x n))) (cond [(empty? lst) empty] [else (cons (first lst) (map (somador (first lst)) (relativa->absoluta (rest lst))))])) 5 / 30

Falta de contexto na recursão Esta função realiza muito trabalho para resolver o problema (tempo de execução de Θ(n 2 )) Se tivéssemos que resolver este problema manualmente, utilizaríamos outro método, o de somar a distância absoluta de um ponto com a distância relativa do próximo Vamos tentar definir uma função mais parecida com este método manual 6 / 30

Falta de contexto na recursão Como é uma função que processa uma lista, começamos com o template (define (rel->abs lst) (cond [(empty? lst)...] [else... (first lst)... (rel->abs (rest lst))...])) Como seria a avaliação de (rel->abs (list 3 2 7))? (rel->abs (list 3 2 7)) (cons... 3... (converte (list 2 7))) (cons... 3... (cons... 2... (converte (list 7)))) O primeiro item da lista deve ser 3, e é fácil calcular este item. Mas o segundo item deve ser (+ 3 2) e a segunda chamada de rel->abs não tem como saber qual era o valor do primeiro item da lista. Este conhecimento foi perdido. 7 / 30

Falta de contexto na recursão Vamos acrescentar um parâmetro acc-dist que representa a distância acumulada, ou seja, a distância absoluta até o ponto anterior Conforme os números da lista são processados, eles são somados a acc-dist O valor inicial de acc-dist precisa ser 0, então definimos rel->abs como uma função local e fazemos a chamada inicial com acc-dist apropriado (define (relativa->absoluta lst0) (define (rel->abs lst acc-dist) (cond [(empty? lst) empty] [else (cons (+ (first lst) acc-dist) (rel->abs (rest lst) (+ (first lst) acc-dist)))])) (rel->abs lst0 0)) 8 / 30

Falta de contexto na recursão No exemplo anterior vimos que a falta de contexto tornou uma função mais complicada do que necessária (e também mais lenta) Veremos a seguir um exemplo em que a falta de contexto faz uma função usar mais memória do que é necessário 9 / 30

Processos iterativos e recursivos

Processos iterativos e recursivos Considere as seguintes implementações para a função que soma dois números naturais utilizando a função add1 e zero? (define (soma a b) (if (zero? b) a (add1 (soma a (sub1 b))))) (define (soma-alt a b) (if (zero? b) a (soma-alt (add1 a) (sub1 b)))) Qual é o processo gerando quando cada função é avaliada com os parâmetros 4 3? 11 / 30

Processos iterativos e recursivos Processo gerado pela expressão (soma 4 3) (soma 4 3) (add1 (soma 4 2)) (add1 (add1 (soma 4 1))) (add1 (add1 (add1 (soma 4 0)))) (add1 (add1 (add1 4))) (add1 (add1 5)) (add1 6) 7 Este processo, caracterizado por uma sequência de operações adiadas é chamado de processo recursivo. Tem um padrão de cresce e diminui 12 / 30

Processos iterativos e recursivos Processo gerado pela expressão (soma-alt 4 3) (soma-alt 4 3) (soma-alt 5 2) (soma-alt 6 1) (soma-alt 7 0) 7 Este processo é chamado de processo iterativo. O espaço necessário para fazer a substituição não depende do tamanho da entrada Neste exemplo, o valor de a foi usado como um acumulador, que guardava a soma parcial O uso de acumulador neste problema reduziu o uso de memória 13 / 30

Recursão em cauda

Recursão em cauda Uma chamada em cauda é a chamada de uma função que acontece dentro de outra função como última operação Uma função recursiva em cauda é aquela em todas as chamadas recursivas são em cauda A forma de criar processos iterativos em linguagens funcionais é utilizando recursão em cauda Os compiladores/interpretadores de linguagens funcionais otimizam as recursões em cauda de maneira que não é necessário manter a pilha da chamada recursiva, o que torna a recursão tão eficiente quando um laço em uma linguagem imperativa. Está técnica é chamada de eliminação da chamada em cauda 15 / 30

Projetando funções com acumuladores

Projetando funções com acumuladores Usar acumuladores é algo que fazemos depois que definimos a função e identificamos a necessidade, e não antes Os princípios para projetar funções com acumuladores são Identificar que a função beneficiasse ou precisa de um acumulador Torna a função mais simples Diminui o tempo de execução Diminui o consumo de memória Entender o que o acumulador significa 17 / 30

Projetando funções com acumuladores Vamos reescrever diversas funções utilizando acumuladores 18 / 30

Exemplo 1 Tamanho de uma lista ;; Lista -> Natural ;; Conta a quantidade de elementos de uma lista. (define tamanho-tests (test-suite "tamanho tests" (check-equal? (tamanho empty) 0) (check-equal? (tamanho (list 4)) 1) (check-equal? (tamanho (list 4 7)) 2) (check-equal? (tamanho (list 4 8-4)) 3))) (define (tamanho lst) (cond [(empty? lst) 0] [else (add1 (tamanho (rest lst)))])) Como o tamanho da resposta não depende do tamanho da entrada, esta função está usando mais memória do que é necessário, portanto ela pode beneficiar-se do uso de acumuladores 19 / 30

Exemplo 1 O conhecimento que se perde na chamada recursiva é a quantidade de elementos já vistos Vamos criar um acumulador que representa esta quantidade (define (tamanho lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (add1 acc))])) (iter lst0 0)) 20 / 30

Exemplo 2 Soma dos elementos de uma lista ;; Lista(Número) -> Número ;; Soma os números de uma lista. (define soma-tests (test-suite "soma tests" (check-equal? (soma empty)0) (check-equal? (soma (list 3)) 3) (check-equal? (soma (list 3 5)) 8) (check-equal? (soma (list 3 5-2)) 6))) (define (soma lst) (cond [(empty? lst) 0] [else (+ (first lst) (soma (rest lst)))])) Como o tamanho da resposta não depende do tamanho da entrada, esta função está usando mais memória do que é necessário, portanto ela pode beneficiar-se do uso de acumuladores 21 / 30

Exemplo 2 O conhecimento que se perde na chamada recursiva é soma dos elementos já vistos Vamos criar um acumulador que representa esta quantidade (define (soma lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (+ (first lst) acc))])) (iter lst0 0)) 22 / 30

Exemplo 3 Inversão de uma lista ;; Lista -> Lista ;; Inverte a ordem dos elmentos de lst. (define inverte-tests (test-suite "inverte tests" (check-equal? (inverte empty) empty) (check-equal? (inverte (list 2)) (list 2)) (check-equal? (inverte (list 2 8 9)) (list 9 8 2)))) (define (inverte lst) (cond [(empty? lst) empty] [else (append (inverte (rest lst)) (list (first lst)))])) Neste caso a função é mais complicada do que o necessário. Isto porque o resultado da chamada recursiva é processada por outra função recursiva (append). Além disso, o tempo de execução desta função é Θ(n 2 ) (o que intuitivamente é muito para inverter uma lista) 23 / 30

Exemplo 3 O conhecimento que se perde na chamada recursiva são os elementos que já foram vistos Vamos criar um acumulador que representa os elementos já vistos (uma lista) (define (inverte lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (cons (first lst) acc))])) (iter lst0 empty)) 24 / 30

Função foldl

Função foldl ;; Observe a semelhanças das funç~oes tamanho, soma e inverte (define (tamanho lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (add1 acc))])) (iter lst0 0)) (define (soma lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (+ (first lst) acc))])) (iter lst0 0)) (define (inverte lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (cons (first lst) acc))])) (iter lst0 empty)) 26 / 30

Função foldl Vamos criar uma função chamada reduz-acc que abstrai este comportamento ;; (X Y -> X) Y Lista(X) -> Y ;; (reduz-acc f base (list x1 x2... xn) devolve ;; (f xn... (f x2 (f x1 base))) ;; Veja a funç~ao pré-definida foldl. (define (reduz-acc f base lst0) (define (iter lst acc) (cond [(empty? lst) acc] [else (iter (rest lst) (f (first lst) acc))])) (iter lst0 base)) 27 / 30

Função foldl Redefinimos as funções em termos de reduz-acc (define (tamanho lst) (define (soma1-no-segundo a b) (add1 b)) (reduz-acc soma1-no-segundo 0 lst)) (define (soma lst) (reduz-acc + 0 lst)) (define (inverte lst) (reduz-acc cons empty lst)) 28 / 30

foldr vs foldl

foldr vs foldl foldr e foldl produzem o mesmo resultado se a função f for associativa Quando possível, utilize a função foldl, pois ela utiliza menos memória Não tenha receio de utilizar a função foldr, muitas funções não podem (ou são mais complicadas) ser escritas em termos de foldl, como por exemplo, map e filter 30 / 30