Programa¸c˜
ao Recursiva
Ricardo Silva
2001/02
1
aAula Pr´
atica
Sintaxe e Semˆ
antica da Linguagem Scheme
1. (Exerc.: 2.2.1)
Converta as seguintes express˜oes aritm´eticas em express˜oes Scheme e avalie-as: a) 1.2 x (2- 1/3) + -8.7
b) (2/3 + 4/9)/(5/11 - 4/3) c) 1 + 1/(2 + 1/(1 + 1/2)) d) 1 x -2 x 3 x -4 x 5 x -6 x 7 2. (Exerc.: 1.2)
Traduza a seguinte express˜ao para nota¸c˜ao prefixa:
5 + 4 + (2 − (3 − (6 +45))) 3(6 − 2)(2 − 7) 3. (Exerc.: 1.3)
Defina um procedimento que tome trˆes n´umeros como argumentos e devolva a soma dos quadrados dos dois maiores.
4. (Exerc.: 1.4)
Observe que o nosso modelo de avalia¸c˜ao permite combina¸c˜oes cujos operadores sejam express˜oes compostas. Use esta observa¸c˜ao para descrever o comporta-mento do seguinte procedicomporta-mento:
(define (a-mais-abs-b a b) ((if (> b 0) + -) a b)) 5. (Exerc.: 1.5)
O Bruno inventou um teste para descobrir se o interpretador de Scheme que est´a a usar avalia as express˜oes de acordo com a estrat´egia de redu¸c˜ao normal ou aplicativa. Ele define os dois procedimentos seguintes:
(define (p) (p)) (define (teste x y)
(if (= x 0) 0 y))
Em seguida avalia a express˜ao (teste 0 (p))
Qual o resultado de avaliar a express˜ao se o interpretador usar a estrat´egia de avalia¸c˜ao aplicativa? E se usar a normal? Explique a sua resposta. (Assuma que a regra de avalia¸c˜ao para a forma especial if ´e independente da estrat´egia utilizada. O predicado ´e avaliado em primeiro lugar e o resultado determina se se avalia o consequente ou a express˜ao alternativa).
2
aAula Pr´
atica
Exemplos de Programa¸
c˜
ao em Scheme
1. (Exerc.: 1.6)
A Alice n˜ao percebe porque ´e que o if tem de ser considerado como uma forma especial. ”Porque ´e que n˜ao o definimos como um procedimento normal a partir do cond?”, pergunta ela. Eva, amiga da Alice afirma que realmente ´e poss´ıvel fazˆe-lo e define uma nova vers˜ao do if :
(define (novo-if predicado ent~ao sen~ao) (cond (predicado ent~ao)
(else sen~ao)))
A Eva mostra `a Alice que o programa funciona: (novo-if (= 2 3) 0 5)
5
(novo-if (= 1 1) 0 5) 0
Encantada, Alice usa o novo-if para reescrever o programa das ra´ızes quadradas: (define (raiz-iter aproxima¸c~ao x)
(novo-if (pr´oximo? aproxima¸c~ao x) aproxima¸c~ao
(raiz-iter (melhora aproxima¸c~ao x) x)))
O que acontece quando a Alice tentar calcular ra´ızes usando o novo progra-ma? Porquˆe?
2. (Exerc.: 1.7)
O teste pr´oximo? usado no c´alculo das ra´ızes quadradas n˜ao ´e muito eficiente para calcular as ra´ızes quadradas de n´umeros muito pequenos (em valor abso-luto). Al´em disso, as opera¸c˜oes aritm´eticas s˜ao sempre efectuadas com precis˜ao limitada, o que torna o nosso teste inadequado para n´umeros demasiado grandes. Explique estas afirma¸c˜oes, com exemplos mostrando como o teste falha em am-bos os casos. Uma estrat´egia alternativa para implementar pr´oximo? consiste em observar a altera¸c˜ao da aproxima¸c˜ao entre duas itera¸c˜oes e para quando essa altera¸c˜ao for uma pequena frac¸c˜ao da aproxima¸c˜ao.
Defina um procedimento raiz-quadrada que use este tipo de teste. O no-vo procedimento funciona melhor para os n´umeros extremamente grandes e os extremamente pequenos?
3. (Exerc.: 1.8)
O m´etodo de Newton para ra´ızes c´ubicas baseia-se no facto de que se y ´e uma aproxima¸c˜ao da raiz c´ubica de x, ent˜ao ´e poss´ıvel encontrar uma melhor aprox-ima¸c˜ao dada pelo valor
(x/y2+ 2y) 3
Use esta f´ormula para implementar um procedimento raiz-c´ubica semelhante ao procedimento raiz-quadrada.
4. (Exerc.: 2.4.2)
Determine o valor da seguinte express˜ao. Explique como obteve esse valor. (let ((x 9))
(* x
(let ((x (/ x 3))) (+ x x)))) 5. (Exerc.: 2.4.3 )
Reescreva as seguintes express˜oes de forma a que n˜ao haja conflitos de so-breposi¸c˜ao das vari´aveis, ou seja, de forma a que uma vari´avel ocorra sempre no ˆambito de um ´unico let ou lambda
a)
(let ((x 7) (y 3))
(+ (let ((x 2))(* x y)) (let ((y 5))(* x y)))) b) (let ((x (/ (expt a b) 4))) (* (let ((x (sqrt x))) (* 2 x)) (let ((x (* 4 x))) (expt (let ((x (sqrt x))) (sqrt x)) (/ (let ((x (* 4 x))) x) (* 2 x)))))) 6. (Exerc.: 1.34 )
Suponha que definimos o procedimento (define (f g) (g 2)) Ent˜ao temos (f quadrado) 4 (f (lambda (z) (* z (+ 1 z)))) 6
O que acontece se (perversamente) pedirmos ao interpretador para avaliar
3
aAula Pr´
atica
Recurs˜
ao e Itera¸
c˜
ao
1. (Exerc.: 1.9)
Cada um dos seguintes dois procedimentos define um m´etodo para adicionar dois inteiros positivos em termos dos procedimentos inc, que incrementa uma unidade ao seu argumento, e dec, que decrementa uma unidade ao seu argu-mento. (define (+ a b) (if (= a 0) b (inc (+ (dec a) b)))) (define (+ a b) (if (= a 0) b (+ (dec a) (inc b))))
Ilustre o processo de avalia¸c˜ao da express˜ao (+ 5 4) por cada um destes procedimentos. S˜ao processos iterativos ou recursivos?
2. (Exerc.: 1.11)
Seja f a fun¸c˜ao definida pela regra
f (n)=n, se n < 3 e
f (n)=f (n - 1) + 2 f (n - 2) + 3 f (n - 3), se n> 3.
Escreva um procedimento que calcule f por meio de um processo recursivo, e outro que calcule f por meio de um processo iterativo.
3. (Exerc.: 1.12)
O seguinte padr˜ao de n´umeros ´e chamado triˆangulo de Pascal. 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 . . .
Os n´umeros fronteiros do triˆangulo s˜ao todos 1, e cada n´umero no interior do triˆangulo ´e a soma dos dois n´umeros acima dele. Escreva um procedimento que calcule os elementos do triˆangulo de Pascal recursivamente.
4. (Exerc.: 1.16)
Escreva um procedimento que calcule a exponencia¸c˜ao iterativamente e que use quadrados suessivos para obter um n´umero de passos logaritmico, como faz exp-rapida.
5. (Exerc.: 1.17)
Os algoritmos de exponencia¸c˜ao que vimos s˜ao baseados na ideia de calcular a exponencia¸c˜ao atrav´es da repeti¸c˜ao da multiplica¸c˜ao. De forma an´aloga, pode-se calcular a multiplica¸c˜ao inteira repetindo a adi¸c˜ao. O seguinte procedimento para a multiplica¸c˜ao ´e an´alogo ao procedimento exp.
(define (* a b) (if (= b 0)
0
(+ a (* a (- b 1)))))
O n´umero de passos deste algoritmo ´e linear em b. Suponhamos agora, que para al´em da adi¸c˜ao, faz´ıamos uso das opera¸c˜oes dobro, que duplica o valor dum inteiro, e metade, que divide um inteiro (par) por 2. Defina ent˜ao um procedimento para a multiplica¸c˜ao an´alogo a exp-rapida, com um n´umero de passos logar´ıtmico.
6. (Exerc.: 1.18)
Usando os resultados dos dois exerc´ıcios anteriores, crie um procedimento iter-ativo para multiplicar dois inteiros em termos da adi¸c˜ao, duplica¸c˜ao e divis˜ao por 2.
4
aAula Pr´
atica
Fun¸
c˜
oes de ordem superior
1. (Exerc.: 1.30)
O procedimento somatorio gera uma recurs˜ao linear. Este procedimento pode ser reescrito para que a soma seja efectuada iterativamente. Mostre como fazˆe-lo preenchendo as express˜oes que faltam na seguinte defini¸c˜ao:
(define (somatorio express~ao a seguinte b) (define (iter a resultado)
(if <??> <??>
(iter <??> <??>))) (iter <??> <??>))
2. (Exerc.: 1.31)
O procedimento somatorio ´e apenas o exemplo mais simples de um grande n´umero de abstrac¸c˜oes semelhantes que podem ser descritas como procedimen-tos de ordem superior. Escreva um procedimento produtorio que devolve o produto dos valores de uma fun¸c˜ao calculados num conjunto de valores dado. Mostre como definir factorial em fun¸c˜ao de produtorio. Use ainda produto-rio para aproximar π usando a f´ormula:
π
4 =
2 · 4 · 4 · 6 · 6 · 8 · ·· 3 · 3 · 5 · 5 · 7 · 7 · ·· Fa¸ca vers˜oes recursiva e iterativa deste procedimento. 3. (Exerc.: 1.32)
Mostre que somatorio e produtorio s˜ao casos particulares de uma no¸c˜ao ainda mais geral que denotaremos acumula que combina uma colec¸c˜ao de termos, usando uma fun¸c˜ao de acumula¸c˜ao qualquer:
(acumula combinador valor-nulo expressao a seguinte b)
acumula toma como argumentos as mesmas especifica¸c˜oes que somatorio e produtorio, juntamente com um procedimento combinador que especifi-ca como o corrente termo deve ser combinado com a acumula¸c˜ao dos termos precedentes, e um valor-nulo que indica qual o valor base a usar quando a fun¸c˜ao ´e invocada sem termos. Escreva acumula e mostre como somatorio e produtorio podem ser definidos a partir de acumula.
Fa¸ca vers˜oes recursiva e iterativa deste procedimento. 4. (Exerc.: 1.33)
Podemos obter uma vers˜ao ainda mais geral de acumula (exerc´ıcio anterior) introduzindo a no¸c˜ao de um filtro nos termos a ser combinados. Isto ´e, combi-namos apenas os termos que satisfazem uma condi¸c˜ao especifica. A abstrac¸c˜ao resultante,acumula-filtrado,tem os mesmos argumentos de acumula, junta-mente com um predicado un´ario adicional, que funciona como filtro. Escreva o procedimento acumula-filtrado. Use este procedimento para expressar: a) a soma dos quadrados dos n´umeros primos no intervalo de a a b (assu-mindo a existˆencia de um predicado primo? )
b) o produto de todos os inteiros positivos menores que n que s˜ao primos entre si com n (isto ´e, todos os inteiros positivos i < n tais que MDC(i,n)=1 ).
5.
Defina a fun¸c˜ao quadrado usando o procedimento
(define exp-curry (lambda (x) (lambda (y) (exp y x)))) 6. (Exerc.: 1.37)
Uma frac¸c˜ao cont´ınua infinita ´e uma express˜ao da forma
f = N1 D1+ N2
D2+D3+···N3
Como exemplo, podemos referir que a expans˜ao infinita em frac¸c˜ao cont´ınua com todos os Ni e os Di iguais a 1 produz 1/φ, onde φ ´e a raz˜ao de ouro. Uma
forma de aproximar uma frac¸c˜ao cont´ınua infinita ´e truncar a expans˜ao ap´os um certo n´umero de termos. Ficamos assim com aquilo a que se chama uma frac¸c˜ao cont´ınua k-termos finita, com a forma:
N1
D1+ N2 . ..+N3
Dk
Suponhamos que n e d s˜ao procedimentos de um argumento (o ´ındice i) que devolvem os Ni e os Di dos termos das frac¸c˜ao cont´ınua. Defina um
procedi-mento frac-cont tal que avaliar (frac-cont n d k) calcule o valor da frac¸c˜ao cont´ınua k-termos finita. Verifique se o procedimento est´a correcto aproximando 1/φ usando
(frac-cont (lambda (i) 1.0) (lambda (i) 1.0) k)
para sucessivos valores de k. Qual o menor k necess´ario para que se obten-ha uma aproxima¸c˜ao correcta at´e 4 casas decimais? Fa¸ca vers˜oes recursiva e iterativa deste procedimento frac-cont.
7. (Exerc.: 1.38)
Em 1737, o matem´atico sui¸co Leonhard Euler publicou De Fractionibus
Con-tinuis, que incluia uma expans˜ao em frac¸c˜ao cont´ınua de e-2, onde e ´e a base dos logaritmos naturais. Nesta frac¸c˜ao, os Nis˜ao todos 1, e os Dis˜ao sucessivamente
1,2,1,1,4,1,1,6,1,1,8,... Escreva um programa que use o procedimento frac-cont do exerc´ıcio anterior para aproximar e, baseado na expans˜ao de Euler.
8. (Exerc.: 1.39)
Uma representa¸c˜ao em frac¸c˜ao cont´ınua da fun¸c˜ao tangente foi publicada em 1770 pelo matem´atico alem˜ao J.H.Lambert:
tanx = x
1 −3−x2x2 5−...
onde x est´a em radianos. Defina um procedimento (tan-fc x k) que com-puta uma aproxima¸c˜ao da fun¸c˜ao tangente baseada na f´ormula de Lambert. k especifica o n´umero de termos a ter em conta, como no exerc´ıcio 5.
9. (Exerc.: 1.40)
Defina um procedimento cubica que possa ser usado conjuntamente com meto-do-newton em express˜oes da forma
(metodo-newton (cubica a b c) 1)
para aproximar zeros da fun¸c˜ao c´ubica x3+ ax2+ bx + c. 10. (Exerc.: 1.41)
Defina um procedimento duplica que toma como argumento um procedimento un´ario e devolve um procedimento que aplica o procedimento original duas vezes. Por exemplo, se inc ´e um procedimento que adiciona 1 ao seu argumento, ent˜ao (duplica inc) ´e um procedimento que adiciona 2 ao seu argumento. Qual ´e o valor devolvido por
(((duplica (duplica duplica)) inc) 5) 11. (Exerc.: 1.42)
Sejam f e g duas fun¸c˜oes un´arias. A composi¸c˜ao f ap´os g ´e a fun¸c˜ao x 7→
f (g(x)). Defina um procedimento composicao que implementa a composi¸c˜ao. Por exemplo,
((composicao quadrado inc) 6) 49
12. (Exerc.: 1.43)
Escreva um procedimento repete que toma como argumentos uma fun¸c˜ao un´ a-ria e um inteiro positivo e devolve a fun¸c˜ao que consiste em n aplica¸c˜oes suces-sivas de f. Por exemplo,
((repete quadrado 2) 5) 625
Pista: Pode ser ´util usar o procedimento do exerc´ıcio anterior. 13. (Exerc.: 1.46)
V´arios dos m´etodos num´ericos descritos neste cap´ıtulo s˜ao instˆancias de uma estrat´egia computacional extremamente geral conhecida como refinamento iter-ativo. Refinamento iterativo significa que para calcular alguma coisa, come¸co com um palpite inicial para a resposta, testo se a resposta ´e suficientemente boa, se n˜ao for melhoro a resposta e continuo o processo, agora com a nova resposta. Escreva um procedimento refinamento-iterativo que toma dois procedimen-tos como argumenprocedimen-tos: um para verificar se uma resposta ´e boa, outro para melhorar uma resposta. refinamento-iterativo deve devolver um procedi-mento que toma uma resposta inicial como arguprocedi-mento e melhora a solu¸c˜ao at´e ser boa. Reescreva os procedimentos raiz-quadrada e ponto-fixo em termos de refinamento-iterativo.
5
aAula Pr´
atica
Estruturas de dados e programa¸
c˜
ao por camadas
1. (Exerc.: 2.1)
Defina uma vers˜ao alternativa de make-racional que funcione para argumentos positivos e negativos. O novo procedimento deve normalizar o sinal de forma a que se o n´umero racional for positivo, tanto o numerador como o denomi-nador devem ter sinais positivos, e se o n´umero racional for negativo apenas o numerador deve ter sinal negativo.
2. (Exerc.: 2.3)
Implemente uma representa¸c˜ao de rectˆangulos no plano. Crie procedimentos que calculem o per´ımetro e a ´area de um dado rectˆangulo, em termos dos con-strutores e selectores usados na representa¸c˜ao dos rectˆangulos. Implemente ago-ra uma representa¸c˜ao diferente dos rectˆangulos. Consegue conceber um sistema para que os mesmos procedimentos de c´alculo da ´area e do per´ımetro funcionem para ambas as representa¸c˜oes?
3. (Exerc.: 2.5)
Mostre que ´e poss´ıvel representar pares de inteiros n˜ao-negativos usando apenas n´umeros e opera¸c˜oes aritm´eticas se representarmos o par a e b como o inteiro 2a3b. Quais s˜ao neste caso as defini¸c˜oes correspondentes aos procedimentos
cons, car e cdr? 4. (Exerc.: 2.6)
Caso a representa¸c˜ao de pares como procedimentos n˜ao tenha sido suficien-temente confusa, reparemos que numa linguagem com a capacidade de ma-nipular procedimentos, n˜ao necessitamos de n´umeros (pelo menos inteiros n˜ ao-negativos) pois podemos implementar o zero e a opera¸c˜ao de acrescentar 1 como (define zero (lambda (f) (lambda (x) x)))
(define (soma-1 n)
(lambda (f) (lambda (x) (f ((n f) x)))))
Esta represent¸c˜ao ´e conhecida como os numerais de Church, em homenagem a Alonzo Church, o inventor do c´alculo λ. Defina um e dois directamente (n˜ao em termos de zero e soma-1). Dˆe uma defini¸c˜ao directa de soma (n˜ao em termos da aplica¸c˜ao repetida de soma-1).
6
aAula Pr´
atica
Listas e opera¸
c˜
oes sobre listas
1. (Exerc.: 2.20)
Os procedimentos +, * e list tomam um n´umero arbitr´ario de argumentos. Uma forma de definir este g´enero de procedimentos ´e atrav´es da nota¸c˜ao ”dotted-tail”. Na defini¸c˜ao de um procedimento, uma lista de parˆametros com um ponto antes do nome do ´ultimo parˆametro indica que, quando o procedimento ´e chamado, os parˆametros iniciais (se existirem) ter˜ao como valores os primeiros argumentos, como usual, mas o valor do ´ultimo parˆametro ser´a uma lista dos restantes argumentos. Por exemplo, dada a defini¸c˜ao
(define (f x y . z) <corpo>)
o procedimento f pode ser chamado com 2 ou mais argumentos. Se avaliar-mos
(f 1 2 3 4 5 6)
ent˜ao no corpo de f, x toma o valor 1, y toma o valor 2, e z a lista (3 4 5 6) . Use esta nota¸c˜ao para escrever uma fun¸c˜ao mesma-paridade que toma um ou mais inteiros e devolve a lista de todos os argumentos que tˆem a mesma paridade do primeiro argumento. Por exemplo,
(mesma-paridade 1 2 3 4 5 6 7) (1 3 5 7) (mesma-paridade 2 3 4 5 6 7) (2 4 6) 2. (Exerc.: 2.21)
O procedimento lista-quadrados toma uma lista de n´umeros e devolve os seus quadrados.
(lista-quadrados (list 1 2 3 4)) (1 4 9 16)
Apresentamos em seguida duas defini¸c˜oes diferentes de lista-quadrados. Complete-as preenchendo as express˜oes assinaladas com ¡??¿.
(define (lista-quadrados elementos) (if (null? elementos)
null
(cons <??> <??>)))
(define (lista-quadrados elementos) (map <??> <??>))
3. (Exerc.: 2.22)
O Lu´ıs tentou reescrever o primeiro procedimento lista-quadrados do exerc´ıcio anterior de forma torn´a-lo iterativo.
(define (lista-quadrados elementos) (define (iter coisas resultado)
(if (null? coisas) resultado
(iter (cdr coisas)
(cons (quadrado (car coisas)) resultado))))
Infelizmente, definir lista-quadrados desta forma faz com que a lista de resposta fique na ordem contr´aria `a desejada. Porquˆe?
Lu´ıs tenta corrigir esta falha trocando os argumentos do cons: (define (lista-quadrados elementos)
(define (iter coisas resultado) (if (null? coisas)
resultado
(iter (cdr coisas) (cons resultado
(square (car coisas)))))) (iter elementos null))
Esta vers˜ao tamb´em n˜ao funciona. Explique porquˆe. 4. (Exerc.: 2.23)
O procedimento for-each ´e semelhante a map. Toma como argumentos um procedimento e uma lista de elementos. Contudo, ao inv´es de formar uma lista de resultados, for-each aplica o procedimento a cada um dos elementos se-quencialmente. Os valores devolvidos por aplicar o procedimento a cada um dos elementos n˜ao s˜ao usados. for-each ´e usado com procedimentos que exe-cutam uma ac¸c˜ao, como imprimir para o ecr˜a. Por exemplo,
(for-each (lambda (x) (newline) (display x)) (list 57 321 88))
57 321 88
Fa¸ca uma implementa¸c˜ao de for-each. 5. (Exerc.: 2.27)
Modifique o procedimento reverse para produzir o procedimento deep-reverse que toma uma lista como argumento e devolve a lista com os seus elementos por ordem inversa e com todas as suas sub-listas invertidas tamb´em. Por exemplo, (define x (list (list 1 2) (list 3 4)))
x ((1 2) (3 4)) (reverse x) ((3 4) (1 2)) (deep-reverse x) ((4 3) (2 1)) 6. (Exerc.: 2.28)
Escreva um procedimento folhas que tem como argumento uma ´arvore e devolve uma lista das folhas da ´arvore, ordenadas da esquerda para a direita. Como exemplo,
(define x (list (list 1 2) (list 3 4))) (folhas x) (1 2 3 4)
7. (Exerc.: 2.29)
Um m´obil bin´ario consiste em dois ramos, um ramo direito e um ramo esquerdo. Cada ramo ´e uma haste com um certo comprimento, da qual est´a suspenso um peso ou ent˜ao outro m´obil bin´ario. Podemos representar um m´obil bin´ario contruindo-o a pertir de dois ramos:
(define (make-mobile left right) (list left right))
Um ramo ´e constru´ıdo a partir de um comprimento (que ´e um n´umero) juntamente com uma estrutura, que pode ser um n´umero (representando um peso) ou outro m´obil.
(define (make-branch length structure) (list length structure))
Escreva os correspondentes selectores ramo-esquerdo e ramo-direito, que devolvem os ramos de um m´obil, e comprimento-ramo e estrutura-ramo que devolvem os componentes de um ramo. Usando os selectores que definiu, defina um procedimento peso-total que devolve o peso total de um m´obil. Um m´obil diz-se equilibrado se as for¸cas de tors˜ao aplicadas pelos seus ramos direito e esquerdo s˜ao iguais (isto ´e, se o comprimento da haste esquerda multiplicado pelo suspenso dessa haste ´e igual ao produto correspondente para a haste direita) e se cada um dos subm´oveis suspensos dos seus ramos estiver equilibrado. Construa um predicado que testa se um m´obil est´a equilibrado. Suponha que alteramos a representa¸c˜ao de m´oveis para que os construtores sejam
(define (make-mobile left right) (cons left right))
(define (make-branch length structure) (cons length structure))
O que ´e necess´ario alterar aos programas j´a escritos para funcionarem de acordo com esta representa¸c˜ao?
8. (Exerc.: 2.30)
Defina um procedimento ´arvore-quadrados, an´alogo a lista-quadrados, ou seja, ´arvore-quadrados deve comportar-se como se segue:
(´arvore-quadrados (list 1
(list 2 (list 3 4) 5) (list 6 7)))
(1 (4 (9 16) 25) (36 49))
Defina ´arvore-quadrados directamente (sem usar procedimentos de ordem superior). Redefina a fun¸c˜ao recorrendo a map.
9. (Exerc.: 2.31)
Na continua¸c˜ao do exerc´ıcio anterior, escreva um procedimento ´arvore-map com a propriedade de ´arvore-quadrados poder ser definido como:
10. (Exerc.: 2.32)
Podemos representar um conjunto como uma lista de elementos distintos, e podemos representar o conjunto dos subconjuntos de um conjunto dado como uma lista de listas. Por exemplo, se conjunto ´e (1 2 3), ent˜ao o conjunto dos seus subconjuntos ´e (() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)). Complete a seguinte defini¸c˜ao de um procedimento que gera o conjunto dos subconjuntos de um conjunto dado.
(define (subconjuntos s) (if (null? s)
(list null)
(let ((resto (subconjuntos (cdr s)))) (append resto (map <??> resto))))) 11. (Exerc.: 2.33)
Complete as seguintes defini¸c˜oes: (define (map p sequencia)
(acumula (lambda (x y) <??>) null sequencia)) (define (append seq1 seq2)
(acumula cons <??> <??>)) (define (length sequencia)
(acumula <??> 0 sequencia)) 12. (Exerc.: 2.34)
A avalia¸c˜ao dum polin´omio pode ser formulada como uma acumula¸c˜ao. Avaliamos o polin´omio
anxn+ an−1xn−1+ ... + a1x + a0
usando um algoritmo conhecido, dito regra de Horner, que estrutura o c´alculo na forma
(...(anx + an−1)x + ... + a1)x + a0)
Por outras palavras, come¸camos com an, multiplicamos por x, somamos an−1,
multiplicamos por x, e assim sucessivamente at´e chegarmos a a0. Complete o seguinte procedimento de forma a que avalie um polin´omio de acordo com a regra de Horner. Assuma que os coeficientes do polin´omio est˜ao ordenados de
a0 a an.
(define (horner-eval x sequencia-coeficientes)
(acumula (lambda (este-coeficiente termos-superiores) <??>) 0
sequencia-coeficientes))
Por exemplo, para calcular 1 + 3x + 5x3+ x5para x = 2 avaliar´ıamos: (horner-eval 2 (list 1 3 0 5 0 1))
13. (Exerc.: 2.35)
Redefina conta-folhas como uma acumula¸cao: (define (count-leaves t)
14. (Exerc.: 2.36)
O procedimento acumula-n ´e semelhante a acumula excepto que tem como terceiro argumento uma sequˆencia de sequˆencias, que se assume terem o mes-mo n´umero de elementos. Aplica o procedimento de acumula¸c˜ao a todos os primeiros elementos das sequˆencias, depois a todos os segundos elementos, e devolve a sequˆencia dos resultados. Tomemos como exemplo uma sequˆencia s que tem quatro sequencias, ((1 2 3)(4 5 6)(7 8 9)(10 11 12)); ent˜ao o valor de (accumulate-n + 0 s) deve ser a sequˆencia (22 26 30). Acabe a defini¸c˜ao de acumula-n.
(define (acumula-n op init seqs) (if (null? (car seqs))
null
(cons (acumula op init <??>) (acumula-n op init <??>)))) 15. (Exerc.: 2.37)
Suponha que representamos vectores v = (vi), como sequˆencias de n´umeros, e
matrizes m = (mij) como sequˆencias de vectores (as colunas da matriz). Por
exemplo, a matriz 1 2 3 4 4 5 6 6 6 7 8 9
´e representada como a sequˆencia ((1 2 3 4)(4 5 6 6)(6 7 8 9)). Com esta representa¸c˜ao podemos usar opera¸c˜oes sobre sequˆencias para exprimir concisa-mente as opera¸c˜oes b´asicas sobre vectores e matrizes. Estas opera¸c˜oes (descritas em qualquer livo de ´algebra linear) s˜ao:
(produto-interno v w ) devolve a somaPiviwi
(matriz-*-vector m v ) devolve o vector t, com ti=Pjmijvj
(matriz-*-matriz m n) devolve a matriz p, com pij =Pkmiknkj
(transposta m) devolve a matriz n onde nij = mji.
podemos definir o produto interno como: (define (produto-interno v w)
(acumula + 0 (map * v w)))
Complete os seguintes procedimentos para calcular as restantes oper¸c˜oes sobre matrizes:
(define (matriz-*-vector m v) (map <??> m))
(define (transposta mat) (acumula-n <??> <??> mat)) (define (matriz-*-matriz m n)
(let ((cols (transposta n))) (map <??> m)))
16. (Exerc.: 2.38)
O procedimento acumula tamb´em ´e conhecido como fold-right, porque com-bina o primeiro elemento da sequˆencia com o resultado de combinar todos os elementos `a direita. Tamb´em existe um fold-left, an´alogo a fold-right, mas que combina os elementos na ordem contr´aria.
(define (fold-left op inicial sequencia) (define (iter resultado resto)
(if (null? resto) resultado
(iter (op resultado (car resto)) (cdr resto))))
(iter inicial sequencia)) Quais os resultados de
(fold-right / 1 (list 1 2 3)) (fold-left / 1 (list 1 2 3))
(fold-right list null (list 1 2 3)) (fold-left list null (list 1 2 3))
Que condi¸c˜ao deve satisfazer op, para que fold-right e fold-left produzam o mesmo resultado?
17. (Exerc.: 2.39)
Complete a seguinte defini¸c˜ao do procedimento reverse `a custa de fold-right e fold-left:
(define (reverse sequence)
(fold-right (lambda (x y) <??>) null sequencia)) (define (reverse sequence)
(fold-left (lambda (x y) <??>) null sequencia)) 18. (Exerc.: 2.40)
Defina um procedimento pares-unicos que, dado um inteiro n, gera a sequˆencia de pares (i,j) com 16 i < j 6 n. Use pares-unicos para simplificar a defini¸c˜ao da fun¸c˜ao soma-pares-primos.
19. (Exerc.: 2.41)
Escreva um procedimento para encontrar todos os triplos ordenados de inteiros positivos distintos i,j e k menores ou iguais a um dado inteiro n e cuja soma totaliza um dado inteiro s.
20. (Exerc.: 2.42)
O problema das oito rainhas consiste em colocar oito rainhas num tabuleiro de xadrez de forma a que nenhuma rainha esteja em cheque por parte de outra (ou seja, garantindo que n˜ao h´a 2 rainhas na mesma linha, coluna ou diagonal). Uma forma de resolver o problema ´e percorrer o tabuleiro colocando uma rainha em cada coluna. Uma vez colocadas k-1 rainhas, temos de colocar a k-´esima numa posi¸c˜ao em que n˜ao ponha em xeque nenhuma das rainhas que j´a estavam no tabuleiro. Podemos formular esta estrat´egia recursivamente: assumindo que ger´amos a sequˆencia de todas as formas v´alidas de colocar k-1 rainhas nas primeiras k-1 colunas. Para cada uma destas hip´oteses, geramos um conjunto colocando um rainha em cada linha da k-´esima coluna. Finalmente filtramos as novas posi¸c˜oes mantendo apenas aquelas em que a nova rainha n˜ao coloca em xeque nenhuma das restantes. Isto produz a sequˆencia de todas as formas v´alidas de colocar k rainhas nas primeiras k colunas do tabuleiro. Continuando este processo encontramos n˜ao apenas uma solu¸c˜ao, mas todas as solu¸c˜oes para o problema.
sequˆencia de todas as solu¸c˜oes do problema de colocar n rainhas num tab-uleiro n × n. rainhas tem um pocedimento interno rainhas-cols que devolve a sequˆencia de todas as formas de colocar rainhas nas primeiras k colunas do tabuleiro.
(define (rainhas tamanho-tabuleiro) (define (rainhas-cols k)
(if (= k 0)
(list tabuleiro-vazio) (filter
(lambda (posicoes) (ok? k posicoes)) (flatmap
(lambda (resto-das-rainhas) (map (lambda (nova-linha)
(junta-posicao nova-linha k resto-das-rainhas)) (enumerate-interval 1 tamanho-tabuleiro))) (rainhas-cols (- k 1)))))) (rainhas-cols tamanho-tabuleiro))
Neste procedimento resto-das-rainhas ´e uma forma de colocar k-1 rain-has nas primeiras k-1 colunas, e nova-linha ´e a linha em que vamos colocar a rainha da k-´esima coluna. Complete o programa implementando uma rep-resenta¸c˜ao para conjuntos de posi¸c˜oes do tabuleiro, incluindo o procedimento junta-posicao, que acrescenta uma nova posi¸c˜ao linha-coluna a um conjunto de posi¸c˜oes, e tabuleiro-vazio que representa um conjunto vazio de posi¸c˜oes. Escreva tamb´em o procedimento ok?, que para um dado conjunto de posi¸c˜oes determina se a rainha da k-´esima posi¸c˜ao est´a ou n˜ao em xeque e devolve #t caso n˜ao esteja.