Você está na página 1de 6

Fundamentos de Programação

Resolução do Segundo Teste

21 de Dezembro de 2007

19:00–20:30

Nome: Número:

1. (1.0) Explique o que são as barreiras de abstracção criadas por um tipo de infor-
mação e quais os inconvenientes de não as respeitar.
Resposta:
As barreiras de abstracção são uma camada conceptual que é estabelecida ao criar um novo
tipo de informação, a qual apenas permite aceder aos elementos do tipo através das suas
operações básicas.
Os inconcenientes de não a respeitar correspondem a perder a abstracção correspondente
ao tipo de informação e à dependência do código desenvolvido das decisões sobre a repre-
sentação do tipo.

2. (1.0) Comente a seguinte expressão: “A documentação de um programa deve ser


efectuada após o código terminado, para garantir que não existem erros nessa mesma
documentação”.
Resposta:
A documentação de um programa começa com a análise do problema e estende-se ao longo
de todo o seu desenvolvimento. É totalmente incorrecto afirmar que a documentação de um
programa deve ser efectuada após o código terminado.

3. (1.0) Quando é que se diz que um objecto tem estado? O que caracteriza o estado
de um objecto?
Resposta:
Um objecto tem estado quando o seu comportamento depende da sua história. O estado de
um objecto é caracterizado por um conjunto de variáveis chamadas variáveis de estado.

4. (1.0) Em que condições se diz que uma variável está não ligada (“unbound") num
dado ambiente?
Resposta:
Uma variável está não ligada num ambiente quando não existe um valor para essa variável
em nenhum dos enquadramentos correspondentes a esse ambiente.

5. (1.0) Diga o que é um ponteiro. Qual a característica que distingue um ponteiro dos
outros tipos de informação?
Resposta:
Um ponteiro é qualquer coisa que aponta. Ao passo que com a utilização de outros tipos
de informação, com os suas entidades estamos fundamentalmente interessados no valor da
entidade, com ponteiros, não estamos interessados no valor do ponteiro, mas sim no valor
para onde ele aponta.
Número: Pág. 2 de 6

6. (1.5) Defina um procedimento chamado otser (resto ao contrário) que recebe como
argumento uma lista e devolve a lista com todos os elementos da lista original ex-
cepto o último. O seu procedimento deve gerar uma mensagem de erro no caso
da lista ser vazia. O seu procedimento deve respeitar as barreiras de abstracção,
utilizando as operações definidas no livro. Por exemplo,

> (otser ‘(3 1 7 5))


(3 1 7)
> (otser ‘(6))
()
> (otser ‘())
otser: a lista não tem elementos

Resposta:

(define (otser lst)


(define (otser-aux lst)
(if (lista-vazia? (resto lst))
(nova-lista)
(cons (primeiro lst)
(otser-aux (resto lst)))))
(if (lista-vazia? lst)
"otser: a lista não tem elementos"
(otser-aux lst)))

7. (1.5) Utilizando os funcionais sobre listas escreva um procedimento que recebe uma
lista de inteiros e que devolve a soma dos quadrados dos elementos da lista. NOTA:
Poderá utilizar qualquer dos procedimentos transforma, filtra e acumula.
Resposta:

(define (soma-quadrados lst)


(acumula + (transforma quadrado lst)))

8. (1.5) Considere a operação potência, em que tanto a base como o expoente são
números naturais. Escreva, usando programação imperativa, um procedimento
que recebe dois números naturais e devolve o resultado de elevar o primeiro à
potência especificada pelo segundo argumento.
Resposta:

(define (potencia b e)
(let ((res 1))
(define (potencia-aux)
(if (= e 0)
res
(begin
(set! res (* res b))
(set! e (- e 1))
(potencia-aux))))
(if (< e 0)
(error "potencia: expoente negativo")
(potencia-aux))))
Número: Pág. 3 de 6

9. (1.5) O seguinte procedimento para calcular os números de Fibonacci usando um


processo recursivo não é eficiente, porque calcula múltiplas vezes o mesmo valor.

(define (fib n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))

Para evitar a repetição de cálculos, podemos imaginar um procedimento com es-


tado interno que vai memorizando os números de Fibonacci, à medida que estes
são calculados. Para isso, este procedimento mantém uma lista com os valores dos
números de Fibonacci que já memorizou, por exemplo, ((0 0) (1 1) (2 1)),
e, sempre que tem de calcular um número de Fibonacci, primeiro vai ver se já sabe
o seu valor e, se não o souber, calcula o seu valor e memoriza-o.
Escreva um procedimento em Scheme para calcular os números de Fibonacci, de
acordo com esta técnica. Recorde que os números de Fibonacci são dados por

 0 se n = 0
f ib(n) = 1 se n = 1

f ib(n − 1) + f ib(n − 2) se n > 1

Resposta:

(define (fib-mem)
(let ((results (list (cons 1 1) (cons 0 0))))
(define (valor-conhecido? n)
(<= n (car (car results))))
(define (valor n resultados)
(if (equal? n (car (car resultados)))
(cdr (car resultados))
(valor n (cdr resultados))))
(define (memoriza n v)
(set! results (cons (cons n v) results)))
(define (calcula-fib n)
(if (valor-conhecido? n)
(valor n results)
(let ((valor-n (+ (calcula-fib (- n 1))
(calcula-fib (- n 2)))))
(memoriza n valor-n)
valor-n)))
(lambda (n)
(calcula-fib n))))
(define fib (fib-mem))

10. (2.0) Desenhe o diagrama de ambientes criado pela seguinte interacão:

(define (cria-garrafa-agua nivel-inicial)


(lambda (valor)
(set! nivel-inicial (- nivel-inicial valor))
nivel-inicial))
Número: Pág. 4 de 6

(define agua-50cl (cria-garrafa-agua 50))


(define agua-33cl (cria-garrafa-agua 33))

(agua-50cl 20)
(agua-50cl 10)
(agua-33cl 33)

Resposta:

cria-garrafa-agua:
agua-50cl:
agua-33cl:

nivel-inicial: 33
0
parâmetros: inivel-inicial
corpo: (lambda (valor) ...)

nivel-inicial: 50
30
20

parâmetros: valor
corpo: (set! ...)
parâmetros: valor nivel-inicial
corpo: (set! ...)
nivel-inicial

11. (2.0) Defina um procedimento cria-contador-limitado que recebe dois nú-


meros inteiros, correspondendo ao limite inferior e superior do contador, e devolve
um objecto que aceita as mensagens inc e dec que permitem, respectivamente,
incrementar e decrementar o valor do contador e devolvem o valor do contador no
final. Se se tentar decrementar o valor do contador para baixo do limite inferior ou
para cima do limite superior deve ser dado um erro e o valor do contador não é
alterado. O contador quando é criado tem como valor o limite inferior. Exemplo:

> (define c1 (cria-contador-limitado 3 7))


> (c1 ’inc)
4
> (c1 ’inc)
5
> (c1 ’dec)
4
> (c1 ’dec)
3
> (c1 ’dec)
Limite inferior atingido
Número: Pág. 5 de 6

Resposta:

(define (cria-contador-limitado min max)


(let ((valor min))
(define (inc)
(if (= valor max)
(error "cria-contador-limitado: limite superior atingido")
(begin
(set! valor (+ valor 1))
valor)))
(define (dec)
(if (= valor min)
((error "cria-contador-limitado: limite inferior atingido")
(begin
(set! valor (- valor 1))
valor)))
(lambda (sol)
(case sol
((inc) (inc))
((dec) (dec))
(else (error "cria-contador-limitado: pedido desconhecido"))))))

12. (1.5) Considerando o trabalho que desenvolveu para o projecto, escreva o procedi-
mento (digito-valido? <cadeia1> <inteiro>) (em que <cadeia1> repre-
senta uma cadeia de caracteres com comprimento 1 e <inteiro> representa a di-
mensão do problema). A chamada (digito-valido? d n) deverá devolver
verdadeiro se e só se d for um valor válido, para a dimensão n. Por exemplo, se
a dimensão for 9, serão válidos todos os dígitos entre 1 e 9.
Resposta:

(define (digito-valido? dig dim)

(define (string-entre? str str1 str2)


(and (string>=? str str1) (string<=? str str2)))

(case dim
((4 9) (string-entre? dig "1" (number->string dim)))
(else (or (string-entre? dig "1" "9")
(string-entre? dig "A" "G")))))

13. (1.5) No contexto do projecto, considere que solução é uma variável global do
tipo matriz que contém a solução de um problema que o utilizador está a re-
solver; cada posição da matriz contém uma cadeia de caracteres com um dígito. Es-
creva o procedimento (digito-possivel? <cadeia1> <inteiro> <inteiro>)
(em que <cadeia1> representa uma cadeia de caracteres com comprimento 1). A
chamada (digito-possivel? d l c) deverá devolver verdadeiro se e só se d
for a escolha certa para a posição da linha l e coluna c.
Resposta:

(define (digito-possivel? dig l c)


(string=? dig (el-matriz solução l c)))
Número: Pág. 6 de 6

14. (2.0) Escreva um procedimento de ordem superior, chamado aplica-vector, que


recebe um vector contendo números e um procedimento de um argumento aplicável
a números e que modifica o vector recebido, aplicando o procedimento a todos os
elementos do vector. Por exemplo, utilizando o procedimento escreve-vector,
podemos obter a seguinte interacção:

> (define v (vector 1 2 3 4 5))


> (escreve-vector v)
[1 2 3 4 5]
> (aplica-vector (lambda (x)(* x x)) v)
> (escreve-vector v)
[1 4 9 16 25]
> (aplica-vector (lambda (x)(* x x)) v)
> (escreve-vector v)
[1 16 81 256 625]

Resposta:

(define (aplica-vector fn v)
(define (aplica-aux n)
(if (>= n 0)
(begin
(vector-set! v n (fn (vector-ref v n)))
(aplica-aux (- n 1)))))
(aplica-aux (- (vector-length v) 1)))

’(BOM NATAL)

Você também pode gostar