Вы находитесь на странице: 1из 180

Introduo Programao

uma Abordagem Funcional

Credin Silva de Menezes, Maria Cludia Silva Boeres,


Maria Christina Valle Rauber, Thais Helena Castro,
Alberto Nogueira de Castro Jnior, Cludia Galarda
Varassin

Departamento de Informtica - UFES


Departamento de Cincia da Computao UFAM
2005

2
CONCEITOS BSICOS
1.1 INTRODUO
Neste curso o leitor estar se envolvendo com a aprendizagem de conceitos e
mtodos bsicos para a construo de programas de computador. A abordagem
que daremos est voltada para o envolvimento do aprendiz com a soluo de
problemas ao invs da atitude passiva de ver o que os outros fizeram. Uma
questo central que permeia o curso a de que construir programas uma tarefa
de engenharia, e que, portanto produzir artefatos com os quais o ser humano
ter de conviver. Artefatos estes que devem satisfazer requisitos de qualidade e
serem, portanto, passveis de constatao.
Optamos desenvolver o curso orientado descrio de funes, um
formalismo bastante conhecido por todos os que chegam a este curso.
Esperamos, com isso, atenuar algumas dificuldades tpicas do ensino introdutrio
de programao. Nas sees seguintes apresentamos alguns conceitos bsicos
que nos parecem importantes ter em mente antes de iniciarmos um curso de
programao.
1.2. COMPUTADORES
Denominamos de computador uma mquina de processar dados, numricos ou
simblicos, que funciona atravs da execuo de programas. Ao contrrio das
inmeras mquinas que conhecemos, tais como: mquina de lavar roupa,
liquidificador, enceradeira, aspirador de p, e tantas outras, que realizam uma
nica funo, o computador uma mquina multiuso. Podemos us-lo como uma
mquina de escrever sofisticada, como uma mquina de fax, como uma prancheta
de desenho sofisticada, como um fichrio eletrnico, como uma planilha de
clculos e de tantas outras formas. exatamente como o nosso conhecido
videogame: para mudar de jogo basta trocar o cartucho. No videogame, cada novo
jogo determinado por um novo programa.
Em linhas gerais podemos entender um computador como uma mquina
capaz de:
a)
b)

interpretar dados que lhe so fornecidos, produzindo resultados


em forma de novos dados ou comportamentos, usando para isso
conceitos que lhe foram antecipadamente informados e,
aceitar a descrio de novos conceitos e consider-los na
interpretao de novas situaes.

Alguns exemplos de uso de um computador:


Ex 1: Descrever para uma mquina a relao mtrica que existe entre os
lados de um tringulo retngulo. De posse desse conhecimento, a mquina
poderia, por exemplo, determinar o valor de um dos lados quando conhecido o
valor dos outros dois.

3
Ex 2: Informar a uma mquina as regras de conjugao de verbos. Com este
conhecimento a mquina pode determinar a forma correta para um determinado
tempo e pessoa de um verbo especfico.
Ex 3: Traduo de textos;
Ex 4: Classificao de textos quanto sua natureza: romance, poesia,
documentrio, entrevista, artigo cientfico;
Ex 5: Manipulao de expresses algbricas, resoluo de integral
indefinida, etc;
Ex 6: Programao automtica: dada uma certa especificao, gerar um
programa eficiente;
Ex 7: Monitoramento de pacientes em um Centro de Tratamento Intensivo;
Ex8: Identificao de tumores no crebro a partir da comparao de imagens
com padres conhecidos de anormalidade;
Ex 9: Roteamento inteligente de mensagens.
1.3. PROGRAMAO
tarefa de identificar o conhecimento necessrio para a descrio de um
conceito, organiz-lo e codific-lo de modo a ser entendido pela mquina damos o
nome de programao de computadores. Ao conhecimento codificado, produto
final da tarefa de programao d-se o nome de programa.
A programao de computadores uma atividade que compreende vrias
outras atividades, tais como: entendimento do problema a ser resolvido,
planejamento de uma soluo, formalizao da soluo usando uma linguagem de
programao, verificao da conformidade da soluo obtida com o problema
proposto.
1.4. LINGUAGEM DE PROGRAMAO
A descrio de conhecimento para um agente racional qualquer (seja uma
mquina ou um humano) subentende a existncia de padres segundo os quais o
agente possa interpretar o conhecimento informado. A esses padres, quando
rigorosamente elaborados, damos o nome de formalismo. Um formalismo
composto de dois aspectos: a sintaxe e a semntica. A sintaxe permite ao agente
reconhecer quando uma "seqncia de smbolos" que lhe fornecida est de
acordo com as regras de escrita e, portanto representa um programa. A semntica
permite que o agente atribua um significado ao conhecimento descrito pela
"seqncia de smbolos". Por exemplo, quando um agente humano (com
determinado grau de escolaridade) encontra a seguinte seqncia de smbolos {3,
4} U {5, 9, 15}, ele por certo reconhecer como uma expresso algbrica escrita

4
corretamente e, se lembrar dos fundamentos da teoria dos conjuntos, associar
esta cadeia como a descrio de um conjunto composto pela unio dos elementos
de dois conjuntos menores.
Eis aqui algumas observaes importantes sobre a necessidade de
linguagens de programao:

Ainda no possvel usar linguagem natural para ensinar o


computador a realizar uma determinada tarefa. A linguagem natural,
to simples para os humanos, possui ambigidades e redundncias
que a inviabilizam como veculo de comunicao com os
computadores.

A linguagem nativa dos computadores muito difcil de ser usada,


pois requer do programador a preocupao com muitos detalhes
especficos da mquina, tirando pois ateno do problema.

Para facilitar a tarefa de programao foram inventadas as linguagens


de programao. Estas linguagens tm por objetivo se colocarem
mais prximo do linguajar dos problemas do que do computador em
si. Para que o programa que escrevemos possa ser entendido pelo
computador, existem programas especiais que os traduzem
(compiladores) ou os que interpretam (interpretadores) para a
linguagem do computador.

Podemos fazer um paralelo com o que ocorre quando queremos nos


comunicar com uma pessoa de lngua estrangeira. Podemos escrever
uma carta em nossa lngua e pedir a algum que a traduza para a
lngua de nosso destinatrio ou se quisermos conversar
pessoalmente, podemos usar um intrprete.

1.5. PROPRIEDADES DE UM PROGRAMA


Fazemos programas com a inteno de dotar uma mquina da capacidade de
resolver problemas. Neste sentido, um programa um produto bem definido, que
para ser usado precisa que sejam garantidas algumas propriedades. Aqui fazemos
referncias a duas delas: a correo e o desempenho. A correo pode ser
entendida como a propriedade que assegura que o programa descreve
corretamente o conhecimento que tnhamos inteno de descrever. O
desempenho trata da propriedade que assegura que o programa usar de forma
apropriada o tempo e os recursos da mquina considerada. Cabe aqui alertar aos
principiantes que a tarefa de garantir que um programa foi desenvolvido
corretamente to complexa quanto prpria construo do programa em si.
Garantir que um programa funciona corretamente condio imprescindvel para
o seu uso e, portanto estaremos dando maior nfase a esta propriedade.
1.6. PARADIGMAS DE LINGUAGENS DE PROGRAMAO

5
As regras que permitem a associao de significados s "seqncias de smbolos"
obedecem a certos princpios. Existem vrias manifestaes destes princpios e a
cada uma delas denominamos de paradigma.
Um paradigma pode ser entendido informalmente como uma forma
especfica de se "pensar" sobre programao. Existem trs grandes grupos de
paradigmas para programao: o procedimental, o funcional e o lgico. Os dois
ltimos so freqentemente referidos como sendo subparadigmas de um outro
mais geral, o paradigma declarativo. O paradigma procedimental subentende a
organizao do conhecimento como uma seqncia de tarefas para uma mquina
especfica. O paradigma lgico requer o conhecimento de um formalismo
matemtico denominado de lgica matemtica. O paradigma funcional baseia-se
no uso dos princpios das funes matemticas. De uma forma geral, os
paradigmas declarativos enfatizam o aspecto correo e o procedimental os
aspectos de desempenho. Vejam que falamos em "enfatizam", o que quer dizer
que apresentam facilidades para descrio e verificao da propriedade
considerada. Entretanto, em qualquer caso, o programador dever sempre
garantir que os dois aspectos (correo e desempenho) sejam atendidos.
1.7. PROGRAMAO FUNCIONAL
Para os fins que aqui nos interessam neste primeiro momento, podemos entender
o computador, de uma forma simplificada, como uma mquina capaz de:
a) avaliar expresses escritas segundo regras sintticas bem definidas, como
a das expresses aritmticas que to bem conhecemos (ex. 3 + 5 - 8)
obedecendo semntica das funes primitivas das quais ela dotada (por
exemplo: as funes aritmticas bsicas como somar, subtrair, multiplicar e
dividir);
b) aceitar a definio de novas funes e posteriormente consider-las na
avaliao de expresses submetidas sua avaliao.
Por enquanto, denominaremos o computador de mquina funcional. A seguir
apresentamos um exemplo de interao de um usurio com a nossa Mquina
Funcional.
usurio: 3 + 5 / 2
sistema: 5,5
usurio: f x y = (x + y) / 2
sistema: definio de f foi aceita
usurio: (f 3 5) + (f 10 40)
sistema: 29

Na primeira interao podemos observar que o usurio descreveu uma


expresso aritmtica e que o sistema avaliou e informou o resultado. Na segunda
interao o usurio descreve, atravs de uma equao, uma nova funo, que ele

6
denominou de f e que o sistema acatou a nova definio. Na terceira interao o
usurio solicita a avaliao de uma nova expresso aritmtica usando o conceito
recentemente definido e que o sistema faz a avaliao usando corretamente o
novo conceito.
1.8. EXPRESSES ARITMTICAS
A nossa mquina funcional hipottica entende a sintaxe das expresses
aritmticas, com as quais todo aluno universitrio j bem familiarizado e capaz
de avali-las usando essas mesmas que regras que j conhecemos.
Sintaxe - Todo operador aritmtico pode ser entendido, e aqui o ser, como
uma funo que possui dois parmetros. A notao usual para as operaes
aritmtica a infixada, ou seja, smbolo funcional colocado entre os dois
operandos. Nada impede de pensarmos nele escritos na forma prefixada, que a
notao usual para funes com nmero de parmetros diferente de 2. Por
exemplo, podemos escrever "+ 3 2" para descrever a soma do nmero 3 com o
nmero 2. As funes definidas pelo programador devem ser escritas de forma
prefixada, como no exemplo de interao acima apresentado. Combinando essas
duas formas, infixada e prefixada, podemos escrever expresses bastante
sofisticadas.
Avaliao - As expresses aritmticas, como sabemos, so avaliadas de
acordo com regras de avaliao bem definidas, efetuando as operaes de acordo
com suas prioridades. Por exemplo, na expresso "3 + 5 / 2" o primeiro operador a
ser avaliado ser o de diviso (/) e posteriormente o de adio. Se desejarmos
mudar essa ordem, podemos usar parnteses em qualquer quantidade, desde que
balanceados e em posies apropriadas. Por exemplo, na expresso "(3 + 5) / 2",
a utilizao de parnteses determina que a sub-expresso 3 + 5 ter prioridade na
avaliao.
1.9. FUNES
Podemos entender o conceito de funes como uma associao entre elementos
de dois conjuntos A e B de tal forma que para cada elemento de A existe apenas
um elemento de B associado. O conjunto A conhecido como o domnio da
funo, ou ainda como o conjunto de entrada, e o conjunto B o contra-domnio
ou conjunto de sada. Para ser mais preciso, podemos afirmar que uma funo f ,
que associa os elementos de um conjunto A aos elementos de um conjunto B,
um conjunto de pares ordenados onde o primeiro elemento do par pertence a A o
segundo a B. Exemplos:
a) Seja a funo T que associa as vogais do alfabeto com os cinco primeiros
inteiros positivos.
T = {(a,1), (e,2), (i,3), (o,4), (u,5)}

7
b) Seja a funo Q, que associa a cada nmero natural o seu quadrado.
Q = {(0,0), (1,1), (2,4), (3,9), (4,16), ...}
Podemos observar que a funo T um conjunto finito e que a funo Q
um conjunto infinito.
1.10. DESCRIES FUNCIONAIS
Podemos descrever um conjunto, de duas formas: extensional, onde explicitamos
todos os elementos que so membros do conjunto, como no caso do conjunto T
apresentado anteriormente; ou na forma intencional, onde descrevemos um
critrio de pertinncia dos membros do conjunto. Por exemplo, o conjunto Q acima
apresentado poderia ser reescrito da seguinte forma:
Q = {(x, y) | x natural e y = x.x} que pode ser lido da seguinte maneira:
Q o conjunto dos pares ordenados (x, y) tal que x um nmero
natural e y o produto de x por x.
Quando descrevemos uma funo para fins computacionais, estamos
interessados em explicitar como determinar o segundo elemento do par ordenado,
conhecido o primeiro elemento do par. Em outras palavras, como determinar y
conhecendo-se o valor de x. Normalmente dizemos que queremos determinar y
em funo de x. Nesta forma de descrio, omitimos a varivel y e explicitamos o
primeiro elemento que denominado ento de parmetro da funo. No caso
acima teramos ento:
Qx=x.x
1.11. Por que comear a aprendizagem de programao atravs do
paradigma funcional?
Tendo em vista a prtica vigente de comear o ensino de programao utilizando
o paradigma procedimental, apresentamos a seguir alguns elementos que
baseiam nossa opo de comear o ensino de programao usando o paradigma
funcional.
1)

O aluno de graduao em Computao tem de 4 a 5 anos para


aprender todos os detalhes da rea de computao, portanto no se
justifica que tudo tenha que ser absorvido no primeiro semestre. O
curso introdutrio apenas o primeiro passo e no visa formar
completamente um programador. Este o momento de apresentarlhe os fundamentos e, alm disso, permitir que ele vislumbre a
variedade de problemas que podem ser solucionados como o apoio
do computador;

2)

O paradigma procedimental requer que o aluno tenha um bom


entendimento dos princpios de funcionamento de um computador
real, pois eles se baseiam, como as mquinas reais, no conceito de
mudana de estados (mquina de Von Neumann).

8
3)

O paradigma lgico, outro forte candidato, requer o conhecimento de


lgica matemtica que o aluno ainda no domina adequadamente;

4)

O paradigma funcional baseado num conhecimento que o aluno j


est familiarizado desde o ensino mdio (funes, mapeamento
entre domnios) o qual ainda explorado em outras disciplinas do
ciclo bsico, o que nos permite concentrar nossa ateno na
elaborao de solues e na descrio formal destas;

5)

O elevado poder de expresso das linguagens funcionais permite


que a abrangncia do uso do computador seja percebida mais
rapidamente. Em outras palavras, podemos resolver problemas mais
complexos j no primeiro curso;

6)

O poder computacional do paradigma funcional idntico ao dos


outros paradigmas. Apesar disso, ele ainda no usado nas
empresas, por vrios aspectos. Dentre os quais podemos citar:
i)

No passado, programas escritos em linguagens funcionais


eram executados muito lentamente. Apesar disso no ser mais
verdadeiro, ficou a fama;

ii)

A cultura de linguagens procedimentais possui muitos adeptos


no mundo inteiro, o que, inevitavelmente, cria uma barreira
introduo de um novo paradigma. Afinal, temos medo do
desconhecido e trememos quando temos que nos livrar de algo
que j sabemos;

iii)

H uma crena que linguagens funcionais so difceis de


aprender e s servem para construir programas de inteligncia
artificial.

7)

A ineficincia das linguagens funcionais em comparao s


procedimentais tem se reduzido atravs de alguns mecanismos tais
como: lazy evaluation, grafo de reduo, combinadores.

8)

Para fazer um programa que "funciona" (faz alguma coisa, embora


no necessariamente o que desejamos) mais fcil faz-lo no
paradigma procedimental. Para fazer um programa que funciona
"corretamente" para resolver um determinado problema mais fcil
no paradigma funcional, pois esse paradigma descreve "o que fazer"
e no "como fazer".

9)

As linguagens funcionais so geralmente utilizadas para


processamento simblico, ou seja, soluo de problemas no
numricos. (Exemplo: integrao simblica X integrao numrica).
Atualmente constata-se um crescimento acentuado do uso deste tipo
de processamento.

10)

A crescente difuso do uso do computador nas mais diversas reas


do conhecimento gera um crescimento na demanda de produo de
programas cada vez mais complexos. Os defensores da
programao funcional acreditam que o uso deste paradigma seja

9
uma boa resposta a este problema, visto que com linguagens
funcionais podemos nos concentrar mais na soluo do problema do
que nos detalhes de um computador especfico, o que aumenta a
produtividade.
11)

Se mais nada justificar o aprendizado de uma linguagem funcional


como primeira linguagem, resta a explicao didtica. Estamos
dando um primeiro passo no entendimento de programao como
um todo. , portanto, importante que este passo seja simplificado
atravs do apoio em uma "mquina" j conhecida, como o caso
das funes.

12)

Ainda um outro argumento: mesmo que tenhamos que usar


posteriormente uma outra linguagem para ter uma implementao
eficiente, podemos usar o paradigma funcional para formalizar a
soluo. Sendo assim, a verso em linguagem funcional poderia
servir como uma especificao do programa.

Exerccios:
1. Conceitue programao de computadores.
2. Quais os principais paradigmas de programao e o que os diferenciam.
3. Faa uma descrio intencional da funo: F = {1,3,5,7,...}.
4, Faa uma listagem de outros exemplos de programas de computador que so
usados hoje em diferentes reas do conhecimento e por diferentes profissionais.
5. Apresente exemplo de outras linguagens tcnicas usadas pelo ser humano para
descrever conhecimento.
6. Os conceitos de correo e de desempenho, se aplicam a qualquer artefato.
Escolha 3 artefatos quaisquer e discuta os dois conceitos.
7. Apresente uma descrio informal da funo que conjuga os verbos regulares
da 1a. conjugao.

2. A Linguagem de Programao Haskell e o ambiente HUGS


2.1. INTRODUO: Neste curso usaremos o ambiente HUGS, no qual utilizada
uma implementao da linguagem de programao funcional Haskell. Essa
linguagem por apresentar uma sintaxe simples e elegante, alm de oferecer
operadores bastante expressivos, tem sido usada com bons resultados para a
aprendizagem de fundamentos de programao.
Podemos usar o HUGS como uma calculadora qualquer, qual submetemos
expresses que ela avalia e nos informa o valor resultante. Vejamos por exemplo
a interao a seguir.
?3+5*2
13
? (3 + 5) * 2
16
?
Nas expresses acima importante destacar o uso do smbolo * (asterisco)
que empregado para representar a multiplicao. Alm desse, outros smbolos
usuais sero substitudos, como veremos logo mais. As operaes aritmticas
so, como sabemos, funes. A notao utilizada em Haskell para as operaes
aritmtica a usual, ou seja, infixada (o smbolo da operao fica entre os
operandos). Uma outra forma que pode ser usada para escrever expresses
usando o operador de forma prefixada. Por exemplo, div 15 6 , indica a diviso
inteira do nmero 15 (dividendo) pelo nmero 6 (divisor).
O smbolo de maior (>) usado pelo sistema para indicar que est preparado
para avaliar uma nova expresso. Aps avaliar uma expresso o Haskell informa o
resultado na linha seguinte e em seguida exibe uma nova interrogao, se
disponibilizando para uma nova avaliao. Podemos explicar o seu funcionamento
conforme o esquema da figura abaixo. Em outras palavras, o ambiente HUGS
estabelece uma repetio para leitura de uma expresso, avaliao de uma
expresso e exibio do resultado, conforme se ilustra no esquema a seguir..

1
1

Podemos usar o ambiente HUGS somente para isso, para escrever


expresses e solicitar ao sistema que as avalie. Entretanto podemos ousar mais e
usar o ambiente para descrever novas funes a partir das funes j oferecidas
pelo ambiente. Podemos tambm utilizar nessas novas definies as prprias
definies que tivermos construdo anteriomente.
2.2. DESCRIO DE FUNES: A forma de descrever funes similar ao que
nos referimos anteriormente no captulo 1, ou seja, atravs de uma equao, onde
no lado esquerdo da igualdade damos um nome funo e relacionamos os
parmetros considerados na sua definio. No lado direito escrevemos uma
expresso utilizando outras funes, primitivas ou no. Isto nos leva portanto a
tomar conhecimento que a linguagem possui funes primitivas que j a
acompanham e que portanto prescindem de definio.
Por exemplo, para definir a funo que determina o espao percorrido por
um mvel em movimento retilneo uniforme, conhecidos a sua velocidade e o
tempo decorrido, podemos escrever:
espaco v t = v * t
No esquema a seguir fazemos uma identificao didtica dos vrios
elementos da definio.O lado esquerdo da igualdade tambm chamado de
inteface ou assinatura da funo e o lado direito o corpo da definio.
espaco
nome da
funo

v t
parmetros

interface da funo

v*t
expresso aritmtica que define a
relao que h entre os parmetros
corpo da definio

Para alimentar o HUGS com novas definies devemos criar um arquivo em


disco no qual editaremos as definies desejadas. Cada arquivo pode ter uma ou
mais definies. Normalmente agrupamos em um mesmo arquivo as definies
relacionadas com a soluo de um problema especfico ou definies de propsito

1
2
geral. No jargo de programao com a linguagem Haskell, um conjunto de
definies denominado de script.
A alimentao de novas definies indicada ao sistema atravs de um
comando que usado no lugar de uma expresso, quando o sistema exibe o seu
pedido de tarefa (o smbolo de interrogao. Para indicar que estaremos dando
um comando usamos o smbolo " : " (dois pontos) seguido do nome do comando
(existem vrios). Para a tarefa que temos neste instante utilizamos o comando
load (oportunamente veremos outros).
Por exemplo, podemos escrever um conjunto de definies em um arquivo
denominado pf0001.hs. Para alimentar este arquivo no ambiente HUGS podemos
escrever:
> :load pf001.hs
A partir deste momento, todas as definies contidas no arquivo informado
estaro disponveis para uso. Podemos entender isso como fazer uma extenso
da mquina Haskell. Na figura 2.1 apresentamos um esquema de utilizao do
ambionete HUGS e de um editor de textos para provimento de novas definies.

Editor
de texto

Arquivo com
definies

Interpretador
HUGS
programador

Figura 2.1 Interaes do Programador com o Ambiente de


Programao

Vale aqui um pequeno lembrete, podemos estender a noo de funes para


incorporar tambm as chamadas funes constantes, ou seja, aquelas que no
possuem domnio, apenas contradomnio. Na nomenclatura de definies dizemos
que temos definies paramtricas e definies no paramtricas.
Por exemplo, podemos definir a constante pi, da seguinte maneira:
pi = 3.1416

1
3
2.3. UM EXEMPLO: Considere que queremos descrever uma funo para
determinar as razes de uma equao do segundo grau.
Sabemos que pela nossa clssica frmula as razes so descritas
genericamente por:

A soluo, como sabemos, formada por um par de valores. Por enquanto


vamos descrever este fato por duas funes, uma para a primeira raiz e outra para
a segunda.
eq2g1 a b c = ((-b) + sqrt (b^2 - 4.0 * a * c )) / (2.0 * a)
Vamos discutir alguns detalhes desta codificao:
o termo -b precisa ser codificado entre parntesis pois nmeros negativos
so obtidos por um operao unria que produz um nmero negativo a partir de
um positivo;
o smbolo da raiz quadrada foi substitudo pela funo sqrt;
o numerador da frao precisa ser delitimado pelo uso de parntesis;
o denominador tambm precisa ser delimitado por parntesis;
o smbolo de multiplicao usual foi trocado pelo * (asterisco);
o smbolo de potenciao foi substitudo pelo ^ (circunflexo).
Podemos agora descrever a outra raiz de forma anloga:
eq2g2 a b c = ((-b) - sqrt (b^2 - 4.0 * a * c )) / (2.0 * a)
Visto que as duas possuem partes comuns, poderamos ter escrito
abstraes auxiliares e produzir um conjunto de definies, tal como:
quad x
raizdelta a b c
dobro x
eq2g1 a b c
eq2g2 a b c

=
=
=
=
=

x*x
sqrt ( quad b - 4.0 * a * c )
2.0 * x
((-b) + raizdelta a b c) / dobro a
((-b) - raizdelta a b c) / dobro a

Vejamos como ficaria uma interao com o HUGS, a partir de um arquivo de


definies denominado eq2g.gs:
> :l eq2g.gs
Reading script file "eq2g.gs":
Haskell session for:

1
4
standard.prelude
eq2g.gs
> eq2g1 2.0 5.0 2.0
-0.5
> eq2g2 2.0 5.0 2.0
-2.0
> eq2g1 3.0 4.0 5.0
Program error: {sqrt (-44.0)}
Podemos observar que houve um problema com a avaliao da expresso
eq2g1 3.0 4.0 5.0
Este um erro semntico, provocado pela tentativa de extrair a raiz
quadrada de um nmero negativo. A funo que definimos portanto uma
funo parcial, ou seja, ela no est definida para todo o domnio dos
reais. Neste caso o sistema apenas acusa o problema ocorrido.
2.4. DEFINIES LOCAIS: As definies que discutimos anteriormente so
globais, no sentido de que esto acessveis ao uso direto do usurio e tambm
disponveis para uso em qualquer outra definio. Por exemplo, se temos o script:
quad x = x * x
hipo x y = sqrt ( quad x + quad y)
Podemos utilizar a definio quad tanto externamente pelo usurio quanto
internamente pela definio hipo.
Se no entanto desejamos construir subdefinies para uso em uma
definio especfica, podemos defini-las internamente, restringindo o seu contexto
A maneira de introduzir definies locais utilizando a clusula where. Vamos
modificar o script acima para que quad s possa ser usado no interior de hipo.
hipo x y

= sqrt ( quad x + quad y)


where
quad x = x * x

As definies internas tambm no precisam ser paramtricas. Veja este


outro exemplo.
hipo x y

= sqrt ( k1 + k2)
where
k1 = x * x
k2 = y * y

1
5
Note que apesar de x e y no serem parmetros de k1 e k2 eles foram
utilizados em suas definies. Isto possvel porque x e y tm validade em todo o
lado direito da definio.
Temos que considerar ainda que nada impede que em uma definio local
tenhamos uma outra definio local e dentro desta outra, e assim sucessivamente.
hipo x y

sqrt k
where
k = quad x + quad y
where
quad x = x * x

2.5. MODELO DE AVALIAO DE EXPRESSES: Quando o avaliador do


HUGS toma uma expresso contendo apenas constantes e operaes primitivas,
ele apenas efetua as operaes obedecendo prioridade dos operadores e
aquelas determinadas pelo uso de parntesis. Por exemplo, para avaliar a
expresso 3 + 5 / 2, primeiro realizada a diviso 5/2, resultando em 2.5, o qual
adicionado ao 3, finalmente obtendo 5.5. Podemos entender isso como uma
seqncia de redues de uma expresso outra mais simples, at que se atinja
um termo irredutvel. Veja os exemplos a seguir:
3 + 5 / 2 3 + 2.5 5.5
(3 + 5) / 2 8 / 2 4
3 + 5 + 2 8 + 2 10
As setas () so usadas para indicar um passo de reduo.
Quando as expresses utilizam funes definidas pelo usurio, o processo
anlogo. Cada referncia uma definio substituda por seu lado direito, at
que se atinja uma expresso bsica, e prossegue como no caso anterior. Vejamos
os exemplos abaixo, considerando a primeira definio de hipo e de quad
apresentada anteriormente:
ordem

expresso

hipo 3 5 + hipo 4 4

sqrt ( quad 3 + quad 5) + hipo 4 4

sqrt ( 3 * 3 + quad 5) + hipo 4 4

sqrt (3 * 3 + 5 * 5) + hipo 4 4

sqrt (3 * 3 + 5 * 5) + sqrt (quad 4 + quad 4)

sqrt (3 * 3 + 5 * 5) + sqrt (4 * 4 + quad 4)

sqrt (3 * 3 + 5 * 5) + sqrt (4 * 4 + 4 * 4)

reduo
aplicada
expresso
inicial
def de hipo
def de
quad
def de
quad
def de hipo
def de
quad
def de

8
9
10
11
12
13
14
15
16

sqrt (9 + 5 * 5) + sqrt (4 * 4 + 4 * 4)
sqrt (9 + 25) + sqrt (4 * 4 + 4 * 4)
sqrt 34 + sqrt (4 * 4 + 4 * 4)
5.83095 + sqrt (4 * 4 + 4 * 4)
5.83095 + sqrt (16 + 4 * 4)
5.83095 + sqrt (16 + 16)
5.83095 + sqrt (32)
5.83095 + 5.65685
11.4878

6
quad
*
*
+
sqrt
*
*
+
sqrt
+

Para uma realizao especfica da linguagem, isso no precisa acontecer


exatamente assim. Entretanto este modelo suficiente para nossos interesses. O
nmero de redues necessrias para chegar forma irredutvel de uma
expresso, tambm denominada de forma cannica ou ainda forma normal, pode
ser usado como critrio para discutir o desempenho da mesma.
Exerccios
1. Estabelea categorias para comparar duas definies;
2. Usando as categorias definidas no item 1 compare as duas definies
apresentadas para as razes de uma equao do segundo grau;
3. Compare usando as suas categorias, as trs definies apresentadas para
hipo;
4. Apresente uma explicao para o erro produzido pela avaliao da
expresso eq2g1 3.0 4.0 5.0
5. Apresente uma seqncia de redues para a expresso:
eq2g1 2.0 5.0 2.0
6. Apresente um conjunto de definies para a funo total para a
determinao das razes de uma equao do segundo grau.
2.6. ASSINATURA DE FUNES E A NOTAO CURRY: Do estudo de
funes sabemos que toda funo possui um domnio e um contradomnio. O
domnio pode ser formado por zero ou mais conjuntos. Quando uma funo no
possui domnio dizemos que uma funo constante. Para descrever este
conhecimento sobre domnio e contradomnio usado o conceito de assinatura,
do ingls signature. Por exemplo, na funo que determina a mdia aritmtica de
3 nmeros reais, temos que o domnio formado pelo produto cartesiano R x R
X R e o contradomnio R.
A assinatura desta funo a seguinte:
ma3 :: R X R X R R

1
7
Em Haskell poderamos ter a seguinte definio:
ma3 x y z = (x + y + z) / 3.
usual tambm dizer R X R X R R o tipo da funo ma3.
Para simplificar o trabalho com funes o matemtico Haskell Cury criou uma
nova notao, que considera que qualquer funo tem sempre um nico
parmetro de entrada. Segundo ele, o resultado de aplicar uma funo sobre um
parmetro produz uma nova funo que pode ser aplicada a outro parmetro, e
assim sucessivamente. Por exemplo, nesta notao, a funo ma3 teria a
seguinte assinatura:
ma3 :: R R R R
Podemos ler da seguinte maneira: ma3 uma funo que mapeia um numero real
em uma nova funo cuja assinatura :
ma3 :: R R R.
A funo ma3 por sua vez mapeia um nmero real em uma nova funo cuja
assinatura :
ma3 :: R R.
A funo ma3 por sua vez mapeia um nmero real em uma nova funo cuja
assinatura :
ma3 :: R.
Que uma funo constante.
Em captulos posteriores veremos as vantagens desta notao introduzida por
Haskell, conhecida por notao Curry. Por enquanto podemos afirmar que essa
facilidade vem do fato que nesta notao as funes possuem propriedades
equivalentes s dos dados.

1
8
3. A Arte de Resolver Problemas
3.1. INTRODUO: O grande objetivo deste curso criar oportunidades para que
o estudante desenvolva suas habilidades como resolvedor de problemas. Mais
especificamente estamos interessados na resoluo de problemas usando o
computador, entretanto, temos certeza, que as idias so gerais o suficiente para
ajudar a resolver qualquer problema.
Embora muitas pessoas j tenham discutido sobre este assunto ao longo da
histria, nosso principal referencial ser o professor George Polya, que escreveu
um livro sobre este assunto, com o mesmo nome deste captulo, voltado para a
resoluo de problemas de matemtica do ensino fundamental. Todos os alunos
deste curso tero grande proveito se lerem este livro.
As idias ali apresentadas com certeza se aplicam com muita propriedade
resoluo de problemas com o computador. Na medida do possvel estaremos
apresentando aqui algumas adaptaes que nos parecem apropriadas neste
primeiro contato com a resoluo de problemas usando o computador.
3.2. DICAS INICIAIS: apresenta-se a seguir algumas orientaes:
3.2.1. S se aprende a resolver problemas atravs da experincia. Logo o
aluno que est interessado em aprender deve trabalhar, buscando resolver por si
mesmo, os problemas propostos antes de tentar o auxlio do professor ou de outro
colega;
3.2.2. A ajuda do professor no deve vir atravs da apresentao pura e
simples de uma soluo. A ajuda deve vir atravs do fornecimento de pistas que
ajudem o aluno a descobrir a soluo por si mesmo;
3.2.3. muito importante no se conformar com uma nica soluo. Quanto
mais solues encontrar, mais hbil o estudante ficar, e alm disso, poder
comparar as vrias alternativas e escolher a que lhe parecer mais apropriada. A
escolha dever sempre ser baseada em critrios objetivos.
3.2.4. Na busca pela soluo de um problema, nossa ferramenta principal o
questionamento. Devemos buscar formular questes que nos ajudem a entender o
problema e a elaborar a soluo.
3.2.5. Aprenda desde cedo a buscar um aprimoramento da sua tcnica para
resolver problemas, crie uma sistematizao, evite chegar na frente de um
problema como se nunca tivesse resolvido qualquer outro problema. Construa um
processo individual e v aperfeioando-o cada vez que resolver um novo
problema.
3.3 COMO RESOLVER UM PROBLEMA: O professor Polya descreve a
resoluo de um problema como um processo complexo que se divide em quatro
etapas, as quais apresentamos aqui, com alguma adaptao. Segundo nos
recomenda Polya, em qualquer destas etapas devemos ter em mente trs
questes sobre o andamento do nosso trabalho, que so: Por onde comear esta
etapa? O que posso fazer com os elementos que disponho? Qual a vantagem de
proceder da forma escolhida?

1
9
Etapa 1 - Compreenso do Problema
impossvel resolver um problema sobre o qual no tenhamos um
entendimento adequado. Portanto, antes de correr atrs de uma soluo,
concentre-se um pouco em identificar os elementos do problema. Faa perguntas
tais como: Quais so os dados de entrada? O que desejamos produzir como
resultado? Qual a relao que existe entre os dados de entrada e o resultado a ser
produzido? Quais so as propriedades importantes que os dados de entrada
possuem?
Etapa 2 - Planejamento
Nesta fase devemos nos envolver com a busca de uma soluo para o
problema proposto. Pode ser que j o tenhamos resolvido antes, para dados
ligeiramente modificados. Se no o caso, pode ser que j tenhamos resolvido
um problema parecido. Qual a relao que existe entre este problema que temos e
um outro problema j conhecido? Ser que podemos quebrar o problema em
problemas menores? Ser que generalizando o problema no chegaremos a um
outro j conhecido? Conhecemos um problema parecido, embora mais simples, o
qual quando generalizado se aproxima do que temos?
Etapa 3 - Desenvolvimento
Escolhida uma estratgia para atacar o problema, devemos ento caminhar
para a construo da soluo. Nesta fase, devemos considerar os elementos da
linguagem de programao que iremos usar, respeitando os elementos
disponibilizados pela linguagem, tais como tipos, formas de definio,
possibilidades de generalizao e uso de elementos anteriormente definidos. A
seguir, devemos codificar cada pedao da soluo, e garantir que cada um esteja
descrito de forma apropriada. Em outras palavras, no basta construir, temos que
ser capazes de verificar se o resultado de nossa construo est correto. Isto
pode ser realizado pela identificao de instncias tpicas, da determinao dos
valores esperados por estas, da submisso dessas instncias ao avaliador e
finalmente, da comparao dos resultados esperados com os resultados
produzidos pela avaliao de nossas definies. Alm disso, devemos garantir
que a definio principal tambm est correta.
Em sntese, a fase de desenvolvimento compreende as seguintes subfases:
1. construo da soluo;
2. planejamento do teste;
3. teste com o computador de mesa;
4. codificao da soluo;
5. teste com o uso do computador.
Etapa 4 - Avaliao do Processo e seus resultados
O trabalho do resolvedor de problemas no pra quando uma soluo est
pronta. Devemos avaliar a qualidade da soluo, o processo que realizamos e
questionar as possibilidades de uso posterior da soluo obtida e tambm do
prprio mtodo utilizado. Novamente devemos fazer perguntas: Este foi o melhor
caminho que poderia ter sido usado? Ser que desdobrando a soluo no
obtenho componentes que poderei usar mais facilmente no futuro? Se esta

2
0
soluo for generalizada possvel reus-la mais facilmente em outras situaes?
Registre tudo, organize-se para a resoluo de outros problemas. Anote suas
decises, enriquea a sua biblioteca de solues e mtodos.
3.4. UM PEQUENO EXEMPLO:
Enunciado: Deseja-se escrever um programa que permita determinar a menor
quantidade de cdulas necessrias para pagar uma dada quantia em Reais.
Etapa 1 Compreenso
Questo: Quais os dados de entrada?
Resposta: A quantia a ser paga.
Questo: Qual o resultado a ser obtido?
Resposta: A menor quantidade de cdulas.
Questo: Qual a relao que existe entre a entrada e a sada?
Resposta: O somatrio dos valores de cada cdula utilizada deve ser igual
quantia a ser paga.
Questo: Existe algum elemento interno, ou seja, uma dado implcito?
Resposta: Sim, os tipos de cdulas existentes.Considere que o Real possui
apenas as seguintes cdulas: 1, 5, 10, 50 e 100. importante observar que
qualquer cdula um mltiplo de qualquer uma das menores.
Etapa 2 - Planejamento
Conheo algum problema parecido? Existe um problema mais simples?
Podemos entender como um problema mais simples um que busque
determinar quantas cdulas de um dado valor so necessrias para pagar a
quantia desejada. Por exemplo, para pagar R$ 289,00 poderamos usar 289
cdulas de R$ 1,00. Ou tambm poderamos usar 5 notas de R$ 50,00, mas
neste caso ficariam ainda faltando R$ 39,00. Claro que no queremos que
falte nem que sobre e, alm disso, desejamos que a quantidade seja mnima.
Parece uma boa estratgia comear vendo o que d para pagar com a
maior cdula e determinar quando falta pagar. O restante pode ser pago com
uma cdula menor, e por a afora. Explorando a instncia do problema j
mencionada, vamos fazer uma tabela com estes elementos.
Expresso para
determinar
a
Quantidade
quantidade de cdulas
cdulas
de um determinado
valor.
289 / 100

de

Quantia a Pagar

289,00
89,00

2
1
89/ 50
39/ 10
9/ 5
4/ 1
TOTAL

1
3
1
4
11

39,00
9,00
4,00
0,00

Etapa 3 - Desenvolvimento
Soluo 1 - Considerando a tabela acima descrita, codificando cada linha
como uma subexpresso da definio.
ncedulas q

(div q 100) +
(div (mod q 100) 50) +
(div (mod (mod q 100) 50) 10) +
(div (mod (mod (mod q 100) 50) 10) 5)+
(div (mod (mod (mod (mod q 100) 50) 10) 5) 1)

Soluo 2 - Considerando uma propriedade das cdulas, ou seja, j que uma


cdula qualquer mltiplo das menores, a determinao do resto no precisa
considerar as cdulas maiores do que a cdula que estamos considerando em um
dado ponto.
ncedulas2 q
= (div q 100) +
(div (mod q 100) 50) +
(div (mod q 50) 10) +
(div (mod q 10) 5)+
(div (mod q 5) 1)
Etapa 4 - Avaliao
A soluo deixa de explicitar as abstraes referentes quantidade de
cdulas de um determinado valor, assim como o resto correspondente. Podemos
questionar, no seria melhor explicitar? Assim poderamos us-las de forma
independente e alm disso, a soluo fica mais clara e portanto inteligvel.
ncedulas q
n100 q
r100 q
n50 q
r50 q
n10 q
r10 q
n5 q
r5 q
n1 q

=
=
=
=
=
=
=
=
=
=

n100 q + n50 q + n10 q + n5 q + n1 q


div q 100
mod q 100
div (r100 q) 50
mod (r100 q) 50
div (r50 q) 10
mod (r50 q) 10
div (r10 q) 5
mod (r10 q) 5
div (r10 q) 5 Erro! O Correto : div (r5 q) 1

2
2
Supondo que no queremos generalizar todas as funes menores ainda
poderamos escrever o programa usando definies locais.

ncedulas q

= n100 + n50 + n10 + n5 + n1


where
n100 = div q 100
r100 = mod q 100
n50 = div r100 50
r50 = mod r100 50
n10 = div r50 10
r10 = mod r50 10
n5 = div r10 5
n1 = mod r10 5

Podemos ainda considerar que se houver uma troca no sistema, de modo a


incluir uma nova cdula que no seja mltiplo de seus valores menores. Seria fcil
mudar o programa para contemplar a mudana nas leis do mundo do problema.
3.5. PROVRBIOS: O professor Polya tambm nos sugere que a lembrana de
alguns provrbios pode ajudar o aprendiz (e o resolvedor de problemas) a
organizar o seu trabalho. Diz Polya que, apesar dos provrbios no se
constiturem em fonte de sabedoria universalmente aplicvel, seria uma pena
desprezar a descrio pitoresca dos mtodos heursticos que apresentam.
Alguns so de ordem geral, tais como:
O fim indica aos meios.
Seus melhores amigos so O que, Por que, Onde, Quando e Como.
pergunte O que, pergunte Por que, pergunte Onde, pergunte Quando e pergunte
Como - e no pergunte a ningum quando precisar de conselho.
No confie em coisa alguma, mas s duvide daquilo que merecer dvida.
Olhe em torno quando encontrar o primeiro cogumelo ou fizer a primeira
descoberta; ambos surgem em grupos.
A seguir apresentamos uma lista deles, organizados pelas etapas s quais
parecem mais relacionados.
Etapa 1 : Compreenso do problema.
Quem entende mal, mal responde.
Pense no fim antes de comear.
O tolo olha para o comeo, o sbio v o fim.

2
3
O sbio comea pelo fim, o tolo termina no comeo.
Etapa 2 : Planejamento da soluo.
A perseverana a me da boa sorte.
No se derruba um carvalho com uma s machadada.
Se no princpio no conseguir, continue tentando.
Experimente todas as chaves do molho.
Veleja-se conforme o vento.
Faamos com pudermos se no pudermos fazer como queremos.
O sbio muda de opinio, o tolo nunca.
Mantenha duas cordas para um arco.
Faa e refaa que o dia bastante longo.
O objetivo da pescaria no lanar o anzol mas sim pegar o peixe.
O sbio cria mais oportunidades do que as encontra.
O sbio faz ferramentas daquilo que lhe cai s mos.
Fique sempre de olho na grande ocasio.
Etapa 3: Construo da soluo.
Olhe antes de saltar.
Prove antes de confiar.
Uma demora prudente torna o caminho seguro.
Quem quiser navegar sem risco, no se faa ao mar.
Faa o que puder e espere pelo melhor.
fcil acreditar naquilo que se deseja.
Degrau a degrau sobe-se a escada.
O que o tolo faz no fim, o sbio faz no princpio.
Etapa 4: Avaliao da soluo.
No pensa bem quem no repensa.
mais seguro ancorar com dois ferros.
Exerccios
1)
Compare as duas definies para a funo que descreve o nmero
mnimo de cdulas para pagar uma quantia q, ncedulas e ncedulas2;
2)
Desenvolva a soluo para o problema da cdulas considerando o
fato de que o Real possui notas de 2 e notas de 20. O que muda?
3)
Apresente trs problemas semelhante ao das cdulas;

2
4)

4
Desenvolva uma soluo para o problema considerando que para
cada tipo de cdula existe um quantidade limitada (maior ou igual a
zero);

2
5
4. ABSTRAO, GENERALIZAO, INSTANCIAO E MODULARIZAO
4.1. INTRODUO: Na busca por resolver um problema podemos usar vrios
princpios, cada um evidentemente ter uma utilidade para a resoluo do
problema, ou para garantia de sua correo ou ainda para facilitar os usos
posteriores da soluo que obtivermos. Apresentamos a seguir alguns deles.
4.2. ABSTRAO: Quando escrevemos uma expresso e no damos nome a
ela, o seu uso fica limitado quele instante especfico. Por exemplo, suponha que
desejamos determinar a hipotenusa de um tringulo retngulo com catetos 10 e 4.
Como conhecemos o teorema de Pitgoras (a2 = b2 + c2), podemos usar
diretamente nossa mquina funcional para avaliar a seguinte expresso:
> sqrt ((10.0 * 10.0)+ (4.0 * 4.0))
10.7703
>
A expresso que codificamos serve apenas para esta vez. Se em algum
outro instante precisarmos avalia-lateremos que codific-la novamente.
Para evitar isso, que damos nomes s nossas expresses, para que
possamos us-las repetidamente, apenas referenciando-as pelo seu nome. No
caso acima, poderamos escrever a definio:
hipotenusa = sqrt ((10.0 * 10.0)+ (4.0 * 4.0))
De posse dessa definio nossa mquina poder avaliar a expresso
sempre que dela precisarmos., basta escreve-la:
> hipotenusa
10.7703
Voc pode agora estar se perguntando, porque no trocamos a definio
para usar diretamente o valor 10.7703?
hipotenusa = 10.7703
Agindo assim a mquina no precisaria avaliar a expresso sqrt ((10.0 *
10.0)+ (4.0 * 4.0)) a cada uso. Por outro lado no ficaria registrada a origem do
valor 10.7703., com o tempo perderamos esta informao. De qualquer forma,
teramos criado uma abstrao qual denominamos hipotenusa.
Outra pergunta pode estar rondando a sua cabea, por que escrever uma
definio que sempre avaliada para o mesmo valor, por que no generaliza-la?
Bom, este foi apenas um recurso didtico para separar os dois conceitos, a
abstrao que acabamos de apresentar a generalizao que apresentaremos a
seguir. No entanto convm lembrar que algumas definies so realmente
constantes e que no so de grande utilidade, como o caso da seguinte definio:

2
6
pi = 3.1416
4.3. GENERALIZAO: Quando uma abstrao se aplica a vrios valores
podemos generaliz-la. Assim, alm de us-la vrias vezes para os mesmos
valores, podemos tambm us-la para valores diferentes. Esta ultima alternativa
evidentemente facilita o seu reuso.
Vamos apresentar duas formas para fazer isso.
a) Elaborando a definio usando outras definies constantes. Por exemplo,
no caso da definio acima para a hipotenusa, poderamos escrever as definies
a seguir:
b = 10.0
c = 4.0
hipotenusa = sqrt (( b * b) + ( c * c))
Aqui, hipo se aplica a dois valores quaisquer b e c, os quais so objetos de
outras definies.
b)Uma forma mais geral atravs do conceito de parametrizao. Esta
consiste em indicar no cabealho da definio (lado esquerdo da igualdade) quais
so os objetos da generalizao. Para o exemplo que estamos trabalhando,
podemos escrever:
hipotenusa b c = sqrt (( b * b) + ( c * c))
Temos ento descrito a funo paramtrica hipotenusa cujos parmetros
so b e c.
4.3.1 INSTANCIAO: A parametrizao permite que usemos a mesma definio
para diferentes instncias do problema. Por exemplo, suponha que desejamos
determinar a hipotenusa de trs tringulos retngulos. O primeiro com catetos 10 e
4, o segundo com catetos 35 e 18 e o terceiro com catetos 9 e 12. Podemos
instanciar a definio paramtrica para estabelecer a seguinte interao:
> hipo 10.0 4.0
10.7703
(5 reductions, 42 cells)
> hipo 35.0 18.0
39.3573
(5 reductions, 43 cells)
> hipo 9.0 12.0
15.0
(5 reductions, 38 cells)
>

2
7
4.4. MODULARIZAO: Em geral, nossos problemas no sero to simples e
diretos quanto o exemplo acima. Quando nos deparamos com problemas maiores,
um bom princpio :
Divida para facilitar a conquista.
Basicamente este princpio consiste em quebrar o problema inicial em
problemas menores, elaborar a soluo para cada um dos problemas menores e
depois combin-las para obter a soluo do problema inicial. A cada um dos
subproblemas encontrados podemos reaplicar o mesmo princpio. Segundo Polya,
esta uma heurstica muito importante qual ele denomina de Decomposio e
Combinao. Antes de pensar em codificar a soluo em uma linguagem de
programao especfica, podemos represent-la atravs de um esquema grfico
denominado de estrutura modular do problema (veja a representao para o
problema a seguir).
4.6. MODULARIZANDO: Considere o problema de descrever rea da figura Fig
4.1 abaixo.

Figura 4.1 Um polgono irregular para o qual desejamos


determinar a sua rea
Como podemos concluir por uma inspeo da figura, no existe uma frmula
pronta para calcular sua rea. Precisamos dividir a figura em partes para as quais
conheamos uma maneira de calcular a rea e que, alm disso, conheamos as
dimenses necessrias.

2
8
Podemos fazer vrias tentativas, como por exemplo, as ilustradas nas figuras
Fig. 4.2 a, Fig. 4.2 b e Fig. 4.2 c.

a
b
c
Figura 4.2 Possveis subdivises do polgono
apresentado na Figura 4.1.

Podemos tentar descrever a rea das figuras menores em cada uma das
figuras apresentadas. Nas figuras 4.2. b e 4.2 c, parece que precisaremos
subdividir novamente. Em 4.2 b a casinha em verde pode ser transformada em um
retngulo e um tringulo. Em 4.2 c a casinha azul (meia-gua) que pode ser
dividida em um retngulo e um tringulo, como na Figura 4.3. E a figura Fig. 4 a,
que podemos dizer?

Figura 4.3 Subdiviso de uma sub-figura da Figura


4.3 c,
Vamos partir para a nossa soluo a partir da figura Fig. 4.2 c. Podemos
dizer que a rea total pode ser obtida pela soma das reas amarela, com rea
vermelha e mais a rea azul. A rea azul pode ser subdividida em azul-claro e
azul-escuro
rea total
rea azul

=
=

rea amarela + rea vermelha + rea azul


rea azulclaro + rea azulescuro

Quando escolhemos as reas acima citadas, no foi por acaso. A escolha foi
baseada na simplicidade do subproblema. Podemos usar este conhecimento para
chegar a um outro. Trs das reas que precisamos calcular so de forma

2
9
retangular. Ou seja, so especializaes de um conceito mais geral. A quarta
rea, tambm pode ser obtida pela especializao do conceito de tringulo
retngulo.
Vamos agora aproximar nossas definies da linguagem de programao.
Portanto podemos escrever:

a_retangulo x y = x * y
O

tringulo que temos retngulo e podemos descrever sua rea por:

a_t_retangulo x y = (x * y) / 2.0
A determinao da rea vermelha nos traz uma pequena dificuldade, no
nos foi informado qual o comprimento da base do retngulo. E agora? Observando
bem a figura podemos concluir que a base do retngulo igual hipotenusa do
tringulo retngulo de catetos a e d.
Podemos escrever ento:
atotal a b c d e
a_azul x y z
hipo x y
a_retangulo x y
a_t_retangulo x y

=
=
=
=
=

a_retangulo a b + a_retangulo (hipo a d) e + a_azul a c d


a_retangulo y z + a_t_retangulo x y
sqrt ( x * x + y * y)
x*y
(x * y) / 2.0

A estrutura da soluo de um problema obtida pela modularizao pode ser


representada por um diagrama denominado de rvore. Para o problema acima
discutido a rvore da forma apresentada na Figura 4.5.

3
0

Figura 4.5 Representao em rvore da estrutura modular do problema clculo


da rea do polgono irregular apresentado na Figura 4.1.
4.7. UM EXEMPLO DETALHADO: Escreva uma descrio funcional para o
volume de cada uma das peas apresentadas nas Fguras 4.6 e 4.7.

Figura 4.6 Pea no. 1

Figuras 4.7 Pea no. 2

Soluo 1: Vamos comear pela Figura 4.6. Uma rpida anlise nos leva a
identificar duas partes. Na parte inferior temos um paraleleppedo, sobre o qual se
assenta um cilindro. Vamos supor que so macios. Chamemos de a, b e c as
dimenses do paraleleppedo, de r o raio da base do cilindro e de h a sua altura. O
volume total da pea pode ser determinado pela soma do volume das duas peas
menores. Chamemos a funo de volfig46, e tentemos uma definio.
volfig46 a b c r h = (a * b * c) + (3.1416 * r * r * h)

3
1
Vamos ento tratar da pea descrita na figura 4.7. Agora identificamos uma
pea apenas. Um paraleleppedo com um furo no centro. Chamemos de a, b e c
as dimenses do paraleleppedo, de r o raio do buraco. Para descrever o volume
da pea devemos subtrair do volume do paraleleppedo o volume correspondente
ao buraco. Chamemos a funo de volfig47, e tentemos uma definio.
Volfig47 a b c r = (a * b * c) - (3.1416 * r * r * c)
Soluo 2: A soluo 1, apesar de resolver o problema, deixa de contemplar
algumas prticas importantes. No tratamento da primeira pea (Figura 4.6), apesar
de identificadas duas peas menores, estas abstraes no foram descritas
separadamente. Ou seja, deixamos de registrar formalmente a existncia de duas
abstraes e com isso no pudemos modularizar a descrio da funo principal.
Podemos tentar ento um outro caminho, contemplando as abstraes para o
cilindro e para o paraleleppedo:
volcil r h
volpar a b c
Volfig46 a b c r h

= 3.1416 * r * r * h
=a*b*c
= volpar a b c + volcil r h

Voltemos ento para a segunda pea (Figura 4.7), e vejamos se podemos


identificar similaridades. Aqui s temos uma pea, que como sabemos, guarda
uma relao com o paraleleppedo da primeira e s. Como podemos encontrar
similaridades? Aprofundando melhor nossa anlise podemos lembrar que o furo
no paraleleppedo, na verdade corresponde a um cilindro que foi retirado. Assim
considerando, podemos ento concluir que o volume da figura 4.7 pode ser obtido
pela diferena entre o volume de um paraleleppedo e de um cilindro. Como j
temos as definies para volume de cilindro e volume de paraleleppedo, s nos
resta escrever a definio final do volume da figura 4.7:
volfig47 a b c r = volpar a b c - volcil r c
Analisando a soluo, podemos tirar algumas concluses:
a) a soluo ficou mais clara,
b) a soluo propiciou o reaproveitamento de definies.
c) se precisarmos usar volume de cilindro e de paraleleppedo isoladamente
ou em outras combinaes, j as temos disponveis.
Consideraes complementares - assim como decidimos descrever
isoladamente o volume de dois slidos, poderamos ter feito o mesmo para as
figuras. As descries das reas de um retngulo e de uma circunferncia podem
ser dadas isoladamente por:
acir r

= pi * r * r

3
2
aret a b = a * b
Podemos reescrever o volume do cilindro e do paraleleppedo da seguinte
maneira:
volcil r h = acir r * h
volpar a b c = aret a b * c
Soluo 3: Se aprofundarmos a anlise podemos observar que as duas
figuras podem ser abstradas como uma s! O cilindro que aparece na primeira,
como um volume que deve ser acrescentado pode ser entendido como o mesmo
cilindro que deve ser subtrado na segunda. Alm disso, podemos estender a
soluo para furos que no vazem a pea, pois a altura do cilindro pode ser
qualquer.
volfig a b c r h = volpar a b c + volcil r h
Podemos observar que esta a mesma definio apresentada anteriormente
para a figura 4.6. O que muda o uso. Para calcular o volume da Figura 4.6
usamos um h positivo e para Figura 4.7 um h negativo.
> volfig 6.0 8.0 2.0 2.0 5.0
158.832
> volfig 6.0 8.0 2.0 2.0 (-2.0)
70.8673

> volfig 6.0 8.0 2.0 2.0 (-1.0)


83.4336

-- determinar o volume de uma instncia da


figura Fig. 1, com um cilindro de raio 2 e altura 5.
-- determinar o volume de uma instncia da
figura Fig. 2, vasada por um furo de raio 2.
-- neste caso fornecemos um valor negativo para
a altura do cilindro com o mesmo valor da altura
do paraleleppedo
-- determinar o volume de uma instncia da
figura Fig. 2, que tem um furo de raio 2 e
profundidade 1.

Exerccios:
1)
2)
3)
4)
5)
6)

Discuta o significado da expresso volfig 6.0 8.0 2.0 2.0 (-5.0). O


que poderia ser feito para contornar este efeito indesejvel?
Resolva o problema da Figura 4.1 usando a modularizao sugerida
pela figura 4.2 b.
Redesenhe a Figura 4.5 (rvore de modularizao) para a soluo
apresentada ao exerccio 2.
Apresente 3 problemas similares para calculo de rea de polgono
irregular.
Apresente 3 problemas similares para calculo de volume de objetos.
Apresente 3 problemas similares em outros domnios de
conhecimento.

3
3
5. Tipos de Dados Numricos
5.1. INTRODUO:
Denominamos de Tipo de Dado a um conjunto de valores, munido de um conjunto
de operaes sobre esses valores. Por exemplo, podemos denominar de T1 ao
tipo de dados formado por um conjunto S de valores idntico aos nmeros
naturais ( S = {0,1,2,3, ...]) e munido das operaes de adio (a) e multiplicao
(m). Cada operao possui uma tipo, indicando o domnio e o contradomnio. Por
exemplo, para o tipo T1, o domnio de a S X S e o contradomnio S. A notao
a seguir usualmente utilizada e em geral denominada de a assinatura da
operao.
a :: S X S S
m :: S X S S
Como visto no captulo 2, em Haskell escreveramos:
a :: S S S
m :: S S S
Em Haskell, conhecendo-se o tipo dos valores de uma expresso podemos
determinar o tipo do valor que dela resultar, ou seja, o seu contra-domnio. Em
linguagens de programao isto equivale a dizer que a linguagem fortemente
tipada. Dizemos ainda que os tipos so elementares ou estruturados. Os
numricos so elementares, assim como tambm o so os tipos lgico e os
caracteres. Neste captulo trataremos dos tipos numricos, os demais viro em
captulos posteriores.
Os nmeros formam um tipo de dados fundamental na computao. Aqui nos
interessa subdividi-los em inteiros e reais. Antes de irmos alm, importante que
se saiba que, sendo o computador composto de elementos finitos, algumas
adaptaes e simplificaes precisam ser feitas para o tratamento de nmeros.
Em HUGS, quando estamos submetendo expresses para avaliao, podemos
desejar que o tipo do resultado seja exibido. Para que isso ocorra, podemos dar
um comando ao HUGS. Para obtermos este comportamento do ambiente,
podemos usar o comando :set, que ativa ou desativa parmetros do ambiente.
Para ativiar um parmetro usamos uma letra correspondente ao parmetro,
precedido do smbolo +. Para desativar usamos o smbolos -. Para saber sobre
outros parametros, experimente submeter apenas o comando :set. A sequencia
de interaes a seguir ilustra a ativao e desativao da exibio do tipo dos
resultados.
> :set +t
> 2^20

3
4
1048576 :: Integer
> :set -t
> 2^100
1267650600228229401496703205376

5.2. NMEROS INTEIROS:


Para trabalhar com nmeros inteiros, a lingugem Haskell prov o tipo Integer, que
pode produzir nmeros que podem ter uma quantidade ilimitada de algarismos,
entretanto, como a memria do computador finita, qualquer que seja a mquina
real que estivermos usando, inevitavelmente esbarraremos em limites. Na
ilustrao a seguir podemos observar essa flexibilidade, quando obtemos o valor
para a expresso 21000, um nmero de 302 algarismos. Claro, o limite pode estar
bem longe e podemos no atingi-lo em nossas aplicaes.
> 2^1000
107150860718626732094842504906000181056140481170553360744375038837
035105112493612249319837881569585812759467291755314682518714528569
231404359845775746985748039345677748242309854210746050623711418779
541821530464749835819412673987675591655439460770629145711964776865
42167660429831652624386837205668069376
Experimente com nmeros maiores! Por exemplo, 9999 9999 um nmero que tem
por volta de 40 mil algarismos. provida ainda uma representao de inteiros
mais restrita, denominada Int. Esta verso trabalha com um intervalo de valores
fixo e reduzido e tem como vantagem economizar memria do computador e
tempo de processamento, usando caractersticas especficas do computador. Para
que um nmero seja representado nesta verso, devemos indicar explicitamente,
como no exemplo a seguir.
> 1234567890::Int
1234567890 :: Int
> 12345678901::Int
Program error: arithmetic overflow
O exemplo a seguir ilustra a diferena entres as duas possibilidades.
> 1089979879870979879
1089979879870979879 :: Integer
> 1089979879870979879::Int
Program error: arithmetic overflow

3
5
O conjunto de operaes associadas ao domnio pode variar, entretanto, em
geral so fornecidas as seguintes operaes primitivas:
Nome

Descrio

Adio

Multiplicao

Subtrao

div

diviso inteira

Potncia

rem

descreve o resto da diviso


inteira entre dois inteiros

mod

Descreve o mdulo da diviso


inteira entre dois inteiros

abs

valor absoluto

signum

produz -1, 0 ou 1, indicando


quando o nmero negativo,
zero ou positivo

Exemplos
> 13 + 15 + 21 + 24 + 27 + 31
131 :: Integer
> 20 * 10 * 98
19600 :: Integer
> 1234 - 4321
-3087 :: Integer
> div 12834 10
1283 :: Integer
> 2^20
1048576 :: Integer
> rem 12834 10
4 :: Integer
> rem (12834 10)
-4 :: Integer
> mod 12834 10
4 :: Integer
> mod (-12834) 10
6 :: Integer
> abs 123
123 :: Integer
> abs (-123)
123 :: Integer
> signum (-3888876527829798)
-1 :: Integer
> signum 0
0 :: Integer
> signum 3
1 :: Integer

Algumas observaes so importantes:


a) As operaes podem ser combinadas para construir expresses mais
complexas;
> 5 + 12 * 3
41 :: Integer
b) As operaes possuem precedncia, ou seja, existe uma ordem em
que devem ser consideradas. No exemplo anterior, a multiplicao (*)

3
6
tem precedncia sobre a adio (+) e portanto realizada antes da
adio. Esta precedncia pode ser modificada pelo uso de parntesis.
> (5 + 12) * 3
51 :: Integer
c) A operao div (diviso) parcial, ou seja, no se aplica quando o
denominador nulo. Quando submetemos uma expresso com esta
caracterstica, o HUGS no avalia a expreso e sinaliza que h um
erro.
> div 398 0
Program error:

divide by zero

5.3. NMEROS REAIS: A denominao em Haskell para a adequao dos reais


aos computadores, denominada de Float. Para este tipo no falaremos de uma
lista de constantes. Ao invs disso falaremos aqui em magnitude e preciso de um
nmero. Como na notao cientfica. A preciso nos diz quantos algarismos
significativos so usados e a magnitude nos diz qual o maior expoente admitido.
Por exemplo, uma determinada implementao pode utilizar 6 algarismos
significativos. Nesta, o nmero 123456.789 seria representado pelo nmero
123457.0, onde o 6 foi arredondado para 7.
A magnitude permite que nmeros bem pequenos e bem grandes sejam
representados.
Por exemplo, um nmero muito grande como
99999999999999999999999999999.0 poderia ser representado por 1.0e+29 e um
nmero bem pequeno como 0.00000000009999999999999999999999999999,
poderia ser representado por 1.0e-010.
> 0.1234567890123456789012345678901234567890
0.123456789012346 :: Double
A representao cientfica utilizada quando necessrio:
> 1234567890123456789012345678.9
1.23456789012346e+027 :: Double
A implementao
denominada Double. Se
uma quantidade menor
explicitar que o nmero
Float.

corrente usa por default um verso estendida


desejarmos, podemos representar os nmeros usando
de algarismos significativos, para isso precisamos
considerado deve ser representado na modalidade

> 0.1234567890123456789012345678901234567890::Float
0.1234568 :: Float
O conjunto de operaes aqui tambm pode variar, entretanto, em geral as
listadas no quadro abaixo so providas.

3
7
Nome
pi
+
*
/
^
sin
cos
tan
sqrt
log
exp

Descrio

Exemplos

> pi
3.14159265358979 :: Double
> 2.5 + 3.3216 + 0.389458
Adio
6.211058 :: Double
> 3.2 * 1.23 * 0.208
Multiplicao
0.818688 :: Double
> 3.456789 - 1.344499089877
Subtrao
2.112289910123 :: Double
> 9.345988 / 234569.34
Diviso
3.98431781408431e-005 :: Double
potncia (o expoente tem que ser Int > 1.5324^10
e positivo)
71.4038177956654 :: Double
> sin pi
Seno
1.22460635382238e-016 :: Doubl
> cos pi
Coseno
-1.0 :: Double
> tan ( pi / 4.0)
Tangente
1.0 :: Double
> sqrt 8.5
raiz quadrada
2.91547594742265 :: Double
> log 2.71828182845905
logaritmo na base e
1.0 :: Double
> exp 1.0
potncia na base e
2.71828182845905 :: Double
a constante 3.14159...

Da mesma forma como ocorre nos nmeros inteiros, nos reais tambm
podemos combinar operaes para construir operaes mais complexas. Tambm
vale para os reais a precedncia de operadores, como nos inteiros podemos usar
parntesis para controlar a ordem em que as operaes sero realizadas.
5.4. CONVERSO DE TIPOS: Em Haskell os inteiros so tratados como um
subconjunto dos reais. Assim, quando temos nmeros reais misturados com
nmeros inteiros em uma mesma expresso, os nmeros inteiros so
automaticamente tratados como reais.
>3+5
8 :: Integer
> 3 + 5.0
8.0 :: Double
Existem funes especficas para converso de tipos:

3
8
a) a funo truncate converte um real x para o menor inteiro menor ou igual x.
> truncate pi
3 :: Integer
b) a funo round converte um real x para o inteiro mais prximo de x, ou seja:
round x = truncate (x + 0.5)
> round pi
3 :: Integer
> round (exp 1)
3 :: Integer

5.5. PRECEDNCIA DOS OPERADORES: Quando aparecem vrios operadores


juntos na mesma expresso, certas regras de precedncia so estabelecidas para
resolver possveis ambigidades. A ordem em que os operadores so
considerados a seguinte:
1) div, mod, abs, sqrt e qualquer outra funo
2) ^
3) * /
4) +, Da mesma forma que na matemtica usual podemos usar os parntesis para
forar uma ordem diferente de avaliao.
Exemplos:
>2+3*5
17
comentrio: o operador * tem precedncia sobre o operador +. Podemos escrever
a expresso a seguir para denotar a seqncia de avaliaes:
2 + 3 * 5 2 + 15 17
> (2 + 3) * 5
25

3
9
comentrio: a ordem de avaliao foi alterada pelo uso dos parntesis. A
seqncia de avaliao portanto:
(2 + 3) * 5 5 * 5 25
> 3 * mod 10 4 + 5
11
comentrio: a primeira prioridade para avaliao do operador mod, seguida da
avaliao do operador * e finalmente do operador +. Podemos escrever a seguinte
seqncia de avaliao:
3 * mod 10 4 + 5 3 * 2 + 5 6 + 5 11
> 3 ^ mod 10 4
9
comentrio : A primeira avaliao do operador mod e em seguida avaliado o
operador ^. A seqncia de avaliao :
3 ^ mod 10 4 3 ^ 2 9

> 4 ^ mod (div 20 4) 2


4
comentrio: A seqncia de avaliao :
4 ^ mod (div 20 4) 2 4 ^ mod 5 2 4 ^ 1 1

5.6. ORDEM DE ASSOCIAO: Quando h ocorrncia de operadores de mesma


precedncia leva-se em considerao a ordem de associao que pode ser
direita ou esquerda.
1. O operador de subtrao faz associao esquerda,
5 - 4 - 2 = (5 - 4) - 2 e no 5 - ( 4 - 2)
2. J o operador de exponenciao faz associao direita,
3 ^ 4 ^ 5 = 3 ^ ( 4 ^ 5 ) e no ( 3 ^ 4 ) ^5

4
0
O uso adequado das noes de precedncia e associao serve tambm
para escrevermos expresses com economia de parntesis.
Observaes:
1. O operador unrio - deve ser sempre representado entre parnteses
quando utilizado junto com outro operador.
1. (- x)^y ou - (x^y) e nunca -x^y ou x^-y.
2. A exponenciao quando repetida em uma expresso avaliada da direita
para a esquerda.
1. 2^3^3 = 2^(3^3).
3. Os demais operadores, na situao acima, so avaliados da esquerda para
a direita.
1. 2 - 3 - 5 = (2 - 3) - 5
2. 2 + 3 + 3 = (2 + 3) + 3
Exemplos:
>3 - 7 - 2
-6
>3*7+4
25
> 3 * ( 7 + 4)
33
> 3 ^ ( 1 + 3)
81
5.6. TIPOS DE NOVAS DEFINIES: Ao definir novas funes, o fazemos
tomando por base os tipos de dados existentes na linguagem. O corpo dessas
definies tem por base a composio das operaes fornecidas por estes tipos
bsicos. Assim, o tipo do dado resultante da avaliao de uma aplicao desta
nova funo, pode ser antecipado por um analisador de tipos, antes mesmo de
avaliar a expresso.
Observe as duas definies a seguir:
media x y = (x + y) / 2
media' x y = truncate ((x + y) / 2)o tipo de dado resultante pela aplicao de
media real, uma vez que a operao / (diviso), s se aplica a nmeros reais.
Da mesma forma, o tipo resultante pela aplicao da funo media inteiro,

4
1
dado que a ultima operao a ser realizada, a truncate, converte reais para
inteiros.
Podemos conferir isso nas submisses de avaliao a seguir:
> media 3 4
3.5 :: Double
5.6. HIERARQUIA DE NMEROS: At agora dissemos que a linguagem Haskell
trabalha com dois tipos numricos, os reais e os inteiros. Isto uma verdade
irrefutvel. Ao avaliar uma expresso numrica o resultado ser sempre um
nmero real ou um nmero inteiro. Entretanto, para facilitar a construo de um
sistema de tipos adequado para a avaliao do tipo de uma expresso, antes
mesmo que ela seja avaliada, tornou-se necessrio a criao de uma hierarquia
de tipos, conforme mostraremos agora.

Ao definir novas funes, o fazemos tomando por base os tipos de dados


existentes na linguagem. O corpo dessas definies tem por base a composio
das operaes fornecidas por estes tipos bsicos. Assim
> media 3 4
3 :: Integer

4
2
>
Exerccios
Qual o tipo resultante da avaliao da definio:
media' x y = div (x + y) 2
O que ocorre na avaliao de uma expresso que usa a definio:
media' x y = div (x + y) 2.0

4
3
6. EXPRESSES LGICAS E O TIPO BOOLEAN

6.1. INTRODUO: Uma caracterstica fundamental dos agentes racionais a


capacidade de tomar decises adequadas considerando as condies
apresentadas pelo contexto onde est imerso. Uma mquina que sabe apenas
fazer contas, ou seja, manusear as operaes aritmticas, ter sua utilidade
fortemente reduzida e, portanto no despertar tantos interesses prticos. Os
computadores que temos hoje so passveis de serem programados para tomada
de deciso, ou seja, possvel escolher entre 2 ou mais aes, qual a que se
deseja aplicar em um determinado instante. Em nosso paradigma de programao
precisamos de dois elementos fundamentais: um tipo de dados para representar a
satisfao ou no de uma condio e um mecanismo que use essas condies na
escolha de uma definio. Neste captulo discutiremos a natureza das proposies
lgicas, sua aplicabilidade na resoluo de problemas e introduziremos um novo
tipo de dados, denominado de boolean. Satisfazendo logo de sada a curiosidade
do leitor lembramos que o nome uma homenagem a George Boole que estudou
e formalizou as operaes com estes tipos de valores.
6.2. PROPOSIES LGICAS: Revirando o ba das coisas estudadas no ensino
fundamental, por certo encontraremos s sentenas matemticas. Lembraremos
ento que elas so afirmaes sobre entes matemticos, tais como os exemplos a
seguir:
1. vinte e dois maior que cinco
2. dois mais trs igual a oito
3. todo nmero primo impar
O conceito de proposio lgica mais geral, aplicando-se s mais diversas
situaes do cotidiano, como nos exemplo a seguir:
1. Maria namorada de Pedro
2. Jos apaixonado por Maria
3. Hoje domingo
Analisando o significado da informao contida em uma proposio lgica
podemos concluir que ela ser uma afirmao verdica, quando se referir a fatos
que realmente acontecem em um determinado mundo. Quando isso no ocorre,
conclumos que elas so inverdicas. Obviamente que isto ir requerer que
possamos ter acesso ao mundo considerado para podermos avaliar uma dada
proposio.
Sentenas Fechadas: as sentenas acima possuem uma caracterstica
importante: todos os seus componentes esto devidamente explicitados.
Denominamos estas sentenas de sentenas fechadas. Uma sentena fechada

4
4
pode ser avaliada imediatamente, conferindo o que elas afirmam com o mundo
sobre o qual elas se referem.
Sentenas Abertas: Um outro tipo de proposio importante so as sentenas
abertas. Nestas, alguns personagens no esto devidamente explicitados e,
portanto a sentena no pode ser avaliada. Quando tratamos sentenas abertas,
antes necessrio instanci-las para algum valor. Por exemplo, a sentena
matemtica,
x + 5 > 10
nem sempre verdadeira, depende do valor que atribuirmos varivel x. Quando
atribumos valores s variveis de uma sentena dizemos que estamos
instanciando a sentena.
No caso acima, podemos instanciar a sentena para os valores 3 e 10, entre
outros, obtendo as seguintes instncias:
1. 3 + 5 > 10
2. 10 + 5 > 10
Agora podemos avali-las e concluir que a segunda verdica e a primeira no.
O mesmo poderia ocorrer com afirmaes de outra natureza, como por exemplo:

Se substituirmos Um certo cidado por Bill Gates, podemos concluir que a


sentena verdica. O mesmo no se pode concluir se a substituirmos pelo nome
de inmeras pessoas que arrancam os cabelos todos os dias, prejudicados que
ficam com o mau funcionamento do citado programa.
Sentenas Compostas: O discurso do cotidiano e at o discurso matemtico,
pode ser escrito como uma lista de proposies simples. Como por exemplo:
1. Hoje domingo
2. Aos domingos tem futebol
3. Quando meu time joga, eu assisto
Nem sempre isto desejvel ou suficiente. Para resolver a questo, podemos
contar com as sentenas compostas. Como por exemplo::
a) Trs menor que cinco e o quatro tambm.;
b) Domingo irei ao futebol ou escreverei notas de aula;
c) Esperanto no uma linguagem de programao.
Observamos ento, o surgimento de trs palavras para criar essas sentenas e
que essas palavras ( e, ou, no) no se referem a coisas, propriedades ou

4
5
fenmenos de um determinado universo. Elas so denominadas de palavras
lgicas, visto que a sua funo na linguagem possibilitar a articulao entre as
proposies do discurso.
A composio de uma proposio pode envolver vrias palavras lgicas, como
nos exemplos a seguir:
1. Dois menor que trs e maior que um mas no maior que a soma de
trs com dois;
2. Maria gosta de Pedro e de Joana mas no gosta de Antonio.
Avaliao de Sentenas Compostas: Para avaliar sentenas simples, vimos que
bastava inspecionar o mundo ao qual ela se refere e verificar se a situao
expressa pela sentena ocorre ou no. E como proceder para as sentenas
compostas? Um caminho que parece confivel apoiar essa avaliao no papel
representado por cada uma das palavras lgicas.
Assim, quando ao considerarmos a proposio:
Hoje fui ao cinema e ao teatro,
s poderemos dizer que ela verdica se tanto a proposio Hoje fui ao cinema
quanto a proposio Hoje fui ao teatro forem avaliadas como verdicas.
Para a proposio composta
Maria foi a missa ou ao cinema,
devemos consider-la como verdica se uma das duas proposies:
1. Maria foi a missa
2. Maria foi ao cinema
forem avaliadas como verdica. E se as duas forem avaliadas como verdicas? No
discurso cotidiano tendemos a pensar nesta situao como inverdica visto que
queramos uma ou outra. A linguagem natural no estabelece se devemos ou no
explicitar que no estamos falando do caso em que ambas podem ser
constatadas. Podemos assumir, portanto, que a nossa sentena composta usando
ou ser avaliada como verdica quando pelo menos uma das duas proposies
que a compe for avaliada com verdica.
No caso da sentena composta usando a palavra lgica no, como em
Hoje no choveu
diremos que ela ser avaliada como verdica quando a proposio Hoje choveu
no puder ser constatada e como inverdica no caso oposto.

4
6
6.3. O TIPO DE DADOS BOOLEAN: Podemos agora discutir sobre a natureza do
valor resultante da avaliao de uma sentena. A avaliao de natureza
funcional, ou seja, dada uma sentena s ela ser mapeada em um de dois valores
distintos. Ento, o contradomnio de uma avaliao um conjunto com apenas
dois valores, um para associar com avaliaes verdicas e outras com as
inverdicas. Podemos escolher um nome para esses valores. Historicamente, as
linguagens de programao os tem denominado de True e False. O primeiro para
associar com as proposies que podem ser constatadas no mundo considerado e
a segunda com as no constatveis.
O tratamento das proposies compostas pode tambm receber um
tratamento formal. Cada uma das palavras lgicas associamos uma funo
matemtica cujo domnio e contradomnio ser o conjunto que acabamos de
definir com as constantes True e False.
aval :: <sentena> {True, False}
Em Hugs nossos operadores so representados por:

Palavra
lgica
e
ou
no

Smbolo em
Hugs
&&
||
not

Vamos ento formalizar a avaliao de sentenas compostas.


Sejam s1 e s2 duas proposies lgicas,
1. O valor lgico da sentena s1 && s2 True se e somente se o valor lgico
de s1 True e o valor lgico de s2 True e False em caso contrrio.
2. O valor lgico da sentena s1 || s2 False se e somente se o valor lgico
de s1 False e o valor lgico de s2 False e True em caso contrrio.
3. O valor lgico da sentena not s1 True se e somente se o valor lgico de
s1 False e False em caso contrrio

4
7

Tabela Verdade: Estas definies tambm podem ser representadas atravs de


uma enumerao de suas associaes, formando o que se costuma chamar de
Tabelas Verdade as quais apresentamos a seguir.
s1
True
True
False
False

s2 s1 && s2
True
True
False False
True
False
False False

s1
True
True
False
False

s2
s1 || s2
True
True
False
True
True
True
False False

s1
not s1
True False
False True

6.4. OPERADORES RELACIONAIS: Quando falamos de proposies lgicas no


discurso matemtico, ou seja, sentenas matemticas, usamos termos tais como:
menor do que, menor ou igual, diferente, entre outros. Estes termos so
fundamentais para a nossa inteno de prover os computadores com a
capacidade de deciso. Denominamos estes elementos de operadores
relacionais, pois estabelecem uma relao de comparao entre valores de um
mesmo domnio. O contradomnio deles do tipo Boolean. A tabela a seguir
apresenta esses operadores, seus significados e exemplos de uso.
significado
operador
==
igualdade
/=
Diferena
<
Menor
<=
Menor ou igual
>
Maior
>=
Maior ou igual

exemplo
(2 + 3) == (8 3)
5 /= (4 * 2 -3)
(2 + 3) < 6
(2 * 3) <= 6
(4 + 2) > (2 * 3)
(8 3 * 2) >= (15 div 3)

resultado
True
False
True
True
False
False

Podemos usar estes operadores para construir novas definies ou


simplesmente, em uma sesso de Hugs para solicitar a avaliao de uma
expresso, como apresentado nos exemplos a seguir.

4
8
> 5 > 4
True :: Bool
> 4 /= (5 + 3)
True :: Bool
> (mod 5 2) == (rem 5 2)
True :: Bool
> (mod (-5) 2) == (rem (-5) 2)
False :: Bool
> (div 5 2) <= truncate(5.0 / 2.0)
True :: Bool

6.5. EXPRESSES E DEFINIES: Agora que temos um novo tipo de dados, ou


seja, um par composto de constantes e funes, podemos p-lo a nosso servio,
escrevendo expresses, de forma to natural quanto aquela que usamos para
escrever expresses aritmticas. Usando essas expresses podemos ento
construir definies cujo tipo resultante seja booleano. Os ingredientes bsicos
para construir essas expresses so os operadores relacionais.
Expresses simples : Por exemplo, para construir uma definio que avalie
se um nmero par, podemos usar a seguinte definio:

par x = (mod x 2) == 0
Vejamos alguns exemplos ilustrados abaixo:

> par 5
False
> par 148
True
> par 0
True
> par (truncate ((5 + 2) / 2))
False

4
9
Outros exemplos de definies:
Verificar se a mltiplo
de b
Verificar se a divisor
de b
Verificar se uma
distncia d igual
diagonal de um
quadrado de lado a
Verificar se um nmero
um quadrado perfeito
Verificar se dois
nmeros a e b so
termos consecutivos de
uma P.A. de razo r

multiplo a b = (mod a b) == 0
divisor a b = multiplo b a

diag d a = (a * sqrt 2.0) == d

quadp n = (sqrt n)^2 == n

spa a b r = (a + r) == b

Expresses compostas : Podemos usar agora os operadores lgicos para


construir expresses compostas. Como nos exemplos a seguir:
Verificar se 3
nmeros esto em
ordem decrescente
Verificar se um
nmero x est no
intervalo fechado
definido por a e b

ordc a b c = (a > b) && (b > c)


pert x a b = (x >= a) && (x <= b)
ou
pert x a b = not ((x < a) || (x > b))

Verificar se um
determinado ponto do
pquad x y = (x > 0) && (y > 0)
espao cartesiano
est no primeiro
quadrante
Verificar se 3 nmeros
a, b e c, so lados de
um tringulo retngulo

tret a b c = ((a^2 + b^2) = = c^2) ||


((a^2 + c^2) = = b^2) ||
((b^2 + c^2) = =a^2)

Quando nossas expresses possuem mais de um operador lgico devemos


observar a precedncia de um sobre o outro. Por exemplo, na expresso:
P || Q && R
onde P, Q e R so expresses lgicas, o operador && ser avaliado primeiro
pois tem precedncia sobre o ||, portanto a expresso ser avaliada para True se
P for avaliado para True ou se a sub-expresso (Q && R) for avaliada para True.

5
0
Podemos modificar esta ordem utilizando parntesis como nas expresses
aritmticas. A expresso acima poderia ser reescrita como:
(P || Q) && R
E agora, para que ela seja avaliada para verdadeira preciso que R seja
avaliada para verdadeira.
Vejamos mais um exemplo de definio:
Verificar se x est fora
do intervalo definido por
fxab
= ((x <=a) || (x >= b)) && (a <= b)
a e b e a e b esto em
ordem no decrescente
Verificar se x menor
que a ou se x maior
g x a b = (x <=a) || (x >= b) && (a <= b)
que b e a e b esto em
ordem no decrescente

6.6. RESOLVENDO UM PROBLEMA: Desejamos verificar se um determinado


ponto do espao cartesiano est dentro ou fora de um retngulo paralelo aos
eixos, conhecidos o ponto, o canto superior esquerdo e o canto inferior direito do
retngulo.
Etapa 1 [Entendendo o problema] O ponto pode estar em qualquer
quadrante? E o retngulo, pode estar em qualquer quadrante? Basta ter os dois
cantos para definir o retngulo? Em que ordem sero informados os cantos?
Como se descreve um canto? Um ponto que esteja sobre um dos lados, est
dentro ou fora do retngulo?
Vamos assumir ento as seguintes decises: discutiremos inicialmente
apenas sobre pontos e retngulos localizados no primeiro quadrante. A ordem em
que os dados sero informados ser: primeiro o ponto, depois o canto superior
esquerdo e por ultimo o canto inferior direito. Para cada ponto sero informadas as
duas coordenadas, primeiro a abscissa e depois a ordenada. Os pontos na borda
so considerados pertencentes ao retngulo.
Etapa 2 [Planejando a Soluo]: Conheo algum problema parecido? Posso
decompor este problema em problemas mais simples? Sei resolver um problema
mais geral em que este um caso particular?
Bom, j nos envolvemos com o problema para verificar se um ponto estava
num intervalo linear, este tambm se refere a intervalo. Verificar se um ponto
pertence a uma regio qualquer do espao n-dimensional mais geral, se eu
conhecesse uma definio para este problema geral, bastaria instanci-la. Ser
que posso decompor o problema na verificao de dois espaos lineares, um
definido pelos lados paralelos ao eixo das ordenadas e outro paralelo ao eixo das
abscissas? Se afirmativo, como combino as duas solues?

5
1
Para que um ponto esteja dentro do retngulo necessrio que sua
ordenada esteja entre as ordenadas dos dois cantos. Sabemos tambm que a
abscissa precisa estar entre as abscissas dos dois cantos. Isso basta? Para
combinar as solues percebemos que suficiente que as duas primeiras estejam
satisfeitas.
Etapa 3 [Construindo a Soluo] Construindo a soluo - Anteriormente j
elaboramos a definio de pertinncia a um intervalo linear, vamos us-la aqui.
pert x a b
=
(x>=a) && (x <= b)
pertinncia linear
pertinncia de
pertsup x y x1 y1 x2 y2 = (pert x x1 x2) && (pert y y2 y1)
superfcie
E o teste, para que valores interessam testar?
Etapa 4 [Analisando a Soluo]: Existem outras maneiras de resolver o
problema? Esta soluo se aplica as outras dimenses?

5
2
7. Definies Condicionais

7.1. INTRODUO: Sabemos de nosso conhecimento matemtico que algumas


funes no so contnuas em um domnio e que, portanto, possuem vrias
definies.
Em muitos casos, o domnio D de uma funo est dividido em regies
disjuntas que se complementam e, para cada uma dessas regies, existe uma
expresso que define o seu mapeamento no contra-domnio. Podemos
representar esta situao pela figura abaixo:

Exemplo 1 - Considere a funo que determina o valor da passagem area


de um adulto, para um determinado trecho, por exemplo, Vitria-Manaus,
considerando a sua idade. Pessoas com idade a partir de 60 anos possuem um
desconto de 40% do valor. Considere ainda que a passagem para o trecho
considerado custa R$ 600,00.
Temos aqui duas formas de calcular o valor da passagem de uma pessoa,
dividindo o domnio em dois subconjuntos. O dos adultos com menos de 60 e o
dos demais.
Podemos definir as duas funes:
vpass1 = 600
vpass2 = vpass1 * 0.6
Para usar uma das definies, temos que explicitamente escolher a que se
aplica ao nosso caso.
Exemplo 2 - Considere a funo que associa com um determinado
rendimento o Imposto de Renda a ser pago. At um determinado valor, o

5
3
contribuinte no paga imposto, e a partir de ento o rendimento dividido em
faixas (intervalos), aos quais se aplicam diferentes taxas. Suponha a tabela
hipottica abaixo.

Faixa
inferior ou igual a 10.800
entre 10.801 e 20.000
entre 20.001 e 30.000
acima de 30.000

alquota
0
10
20
25

Desconto
0
1000
1500
1800

Para descrever as vrias definies e os correspondentes subdomnios,


poderamos escrever separadamente cada definio, construindo portanto vrias
funes, e deixar que o usurio escolha qual usar. Claro que isto traria muitos
inconvenientes pois estaramos deixando uma escolha mecnica na mo do
usurio, que alm de sobrecarreg-lo com tarefas desnecessrias, ainda estaria
expondo-o ao erro por desateno. Mas vamos l construir as funes
independentes.
ir1 s = 0
ir2 s = s * 0.1 - 1000
ir3 s = s * 0.2 - 1500
ir4 s = s * 0.25 - 1800
Agora, para us-las, o usurio pega o seu salrio, olha a tabela e seleciona
qual funo aplicar.
A escolha de qual definio usar para uma dada situao, em si, um tipo
de computao. Podemos descrever essa computao com expresses
condicionais, vamos deixar que o computador escolha. Descrevemos cada
subdomnio com a respectiva funo aplicvel e deixemos que ele escolha a
definio a aplicar, dependendo do valor fornecido. Vejamos ento como isso
pode ser feito nas sees subsequentes.
7.2. A ESTRUTURA IF: Uma expresso condicional construda com if possui a
seguinte sintaxe:
if <expresso lgica> then <expresso 1> else <expresso 2>
onde:

5
4

<expresso lgica>

<expresso1> e
<expresso2>

Uma expresso descrevendo uma condio a ser


satisfeita, envolvendo operadores relacionais e
operadores lgicos.
1. Expresses descrevendo um valor a ser produzido
como resposta entrada fornecida e, como a
expresso total tem que ser de um nico tipo, as
duas expresses devem ser do mesmo tipo.
2. Cada uma destas expresses pode ser inclusive
uma outra condicional, dentro da qual pode haver
outras e assim sucessivamente.
3. Quando a <expresso lgica> avaliada para
True o valor resultante ser o que for obtido pela
avaliao da <expresso 1> caso contrrio ser o
obtido pela avaliao da <expresso 2>

Para a funo que calcula o valor da passagem area podemos ento construir a
seguinte definio:
vpass x = if x < 60 then 600 else 360
rvore de deciso: Podemos representar as expresses condicionais atravs de
uma notao grfica denominada de rvore de deciso. importante considerar
que este tipo de representao uma ferramenta importantssima para
estruturarmos a soluo de problemas que requerem expresses condicionais.

Exemplo 3 Definir a funo que determina o valor absoluto de um


nmero. Sabemos que esta funo se define em dois subdomnios:
subdomnio
x<0
x >= 0

expresso
-x
x

5
5
Como s temos duas possibilidades, podemos codificar da seguinte maneira:
absoluto x

= if x < 0 then -x else x

Para concluir esta apresentao voltemos ao nosso exemplo 2 que definie a


funo para calculo do Imposto de Renda. O domnio neste caso deve ser
quebrado em quatro subdomnios e para cada um deles construiremos uma
expresso.
domnio
s 10800
pert s 10801 20000
pert s 20001 30000
s > 30000

funo
ir1 s
ir2 s
ir3 s
ir4 s

Para codificar precisaremos ir quebrando sucessivamente o domnio da


funo. Primeiro dividimos entre o primeiro intervalo e o resto, depois dividimos o
resto entre o segundo intervalo e o resto e assim sucessivamente.
A codificao final pode ser:

ir s = if s <= 10800
then ir1
else if pert s 10800 20000
then ir2
else if pert s 20001 30000
then ir3
else ir4
where
ir1 = 0
ir2 = s * 0.1 - 1000
ir3 = s * 0.2 - 1500
ir4 = s * 0.25 - 1800
pert x a b = x>=a && x<=b

7.2.1 USANDO O IF
EXEMPLO 1: Considere um mapeamento de valores numricos onde o domnio
se divide em 4 regies, cada uma das quais possui diferentes formas de
mapeamento. As regies so apresentadas na figura abaixo, numeradas da

5
6
esquerda para direita. Observe ainda que as extremidades so abertas. Considere
ainda a seguinte tabela de associaes:

regio
regio 1
regio 2
regio 3
regio 4

mapeamento desejado
o dobro de x
o sucessor de x
o quadrado de x
o simtrico do quadrado de x

Podemos analisar as regies atravs do seguinte diagrama:

X<0
True

X < -15
True

False

False

X > 10
True

False

5
7
O que nos levar seguinte definio:
f x = if x < 0
then if x
then
else
else if x
then
else

<
2
x
<
x
-

(-15)
* x
+ 1
10
^2
(x ^ 2)

Exemplo 2: Dados 3 nmeros inteiros distintos, determinar o maior deles.


Podemos explorar uma soluo da seguinte maneira. Considere um
retngulo e divida-o horizontalmente em 2 partes, a parte de cima representa as
situaes onde a > b e a de baixo aquelas onde b > a. Divida agora o retngulo
verticalmente, em cada uma das regies anteriores surgiro 2 metades. Na de
cima, representamos agora a relao entre a e c. Na de baixo, a relao entre b e
c.

Explorando as relaes entre os Representando as relaes atravs de


nmeros
uma rvore de deciso
Traduzindo a rvore de deciso para Hugs, chegamos seguinte definio:
maior a b c =

if a > b
then if a > c
then a
else
c
else if b > c
then
b
else
c

5
8
7.3 DEFINIES PROTEGIDAS (guarded commands): A estrutura IF foi
apresentada por primeiro por questes histricas, por tratar-se de uma forma
pioneira de escrever definies condicionais. Entretanto, algumas vezes podemos
lanar mo de estruturas mais simples e mais legveis.
As definies protegidas, tambm conhecidas por guarded commands permitem
que se escreva para uma mesma funo, vrias definies, cada uma delas
protegida por uma expresso lgica.

<nome da funo> <parmetros> | <proteo 1>


| <proteo 2>
| <proteo 3>
. . .
| <proteo n>
[ | otherwise

= <definio 1>
= <definio 2>
= <definio 3>
= <definio n>
= <definio n + 1> ]

A ltima clausula da definio opcional, por este motivo est apresentada dentro
de colchetes.
Vejamos como podemos reescrever a definio da nossa funo ir para clculo
do imposto de renda.

ir' s | s<=10800
= ir1
| pert s 10800 20000 = ir2
| pert s 20001 30000 = ir3
|otherwise
= ir4
where
ir1 = 0
ir2 = s * 0.1 - 1000
ir3 = s * 0.2 - 1500
ir4 = s * 0.25 - 1800

Exerccios
1. Reescreva, usando definies protegidas. a definio da funo que
determina o maior de 3 nmeros inteiros fornecidos.

5
9

8. O TESTE DE PROGRAMAS
8.1. INTRODUO: No basta desenvolver um programa para resolver um dado
problema. preciso garantir que a soluo esteja correta. Muitos erros podem
ocorrer durante o desenvolvimento de um programa e, portanto temos que garantir
que o programa que ir ser executado est livre de todos eles. Ao conceber a
soluo podemos nos equivocar e escolher caminhos errados, precisamos
eliminar esses equvocos. Ao codificarmos a nossa soluo podemos cometer
outros erros ao no traduzirmos corretamente nossa inteno. Esses erros podem
ocorrer por um mau entendimento dos elementos da linguagem ou at mesmo por
descuido, o certo que eles ocorrem. Uma estratgia muito til, mas no infalvel,
o teste de programa.
Em sua essncia, o teste de programa consiste em submeter um programa
ao exerccio de algumas instncias do problema e comparar os resultados
esperados com os resultados obtidos.
8.2. O PROCESSO DE TESTE: Em primeiro lugar devemos escolher as
instncias apropriadas, no basta escolh-las aleatoriamente. A seguir devemos
determinar, sem o uso do programa, qual o valor que deveria resultar quando o
programa for alimentado com essas instncias. O passo seguinte consiste em
submeter cada instncia ao programa e anotar o resultado produzido por ele.
Finalmente devemos comparar cada valor esperado com o valor produzido e
descrever qual o tipo de ocorrncia.
Um exemplo: Considere o problema de identificar se um dado ponto est
ou no localizado no primeiro quadrante do espao cartesiano. Considere ainda
que concebemos a seguinte definio:

primquad x y

(x >= 0) && (y >= 0)

Precisamos agora verificar se ela atende nossa inteno. Para tanto


devemos escolher algumas instncias, prever o resultado esperado e em seguida
submeter ao HUGS, para ver o que acontece.
Que pares de valores deveremos escolher? Bom, vamos escolher uns
pares usando a seguinte estratgia: um par onde x maior que y, outro onde y
seja maior que x e um terceiro em que os dois sejam iguais. Gerando uma planilha
como apresentada a seguir.

6
0

x
-5
-2
5

resultado resultado
diagnstico
esperado obtido
-2
False
-5
False
5
True
y

Podemos agora submeter as instncias avaliao do sistema, obtendo a


seguinte interao:
? primquad (-5) (-2)
False
? primquad (-2) (-5)
False
? primquad 5 5
True
?
Podemos agora completar o preenchimento de nossa planilha, obtendo a tabela a
seguir:
resultado resultado
diagnstico
esperado obtido
-5 -2
False
False
sucesso
-2 -5
False
False
sucesso
5 5
True
True
sucesso
x

Verificando as diversas linhas da coluna Diagnstico, parece que nosso


programa est correto. Veja que ele passou com sucesso em todos os testes!
Que pena que no seja verdade. Apesar de passar em todos os testes a
que foi submetido, ele no funciona corretamente. Tudo que podemos afirmar
neste instante que para os valores usados, o programa funciona corretamente. E
para os outros valores, ser que funciona corretamente?
Outros valores? Quais?
8.3. PLANO DE TESTE: Para escolher os valores que usaremos, antes de mais
nada devemos identificar as classes de valores que sero relevantes para o teste,
em um segundo instante podemos ento escolher os representantes destas
classes. Quando temos um parmetro, os possveis valores a serem usados so
todas as constantes do domnio. Para o caso de um parmetro do tipo int, existem
65536 valores diferentes. Testar nosso programa para todos esses valores
implicaria em determinar a mesma quantidade de resultados esperados e em

6
1
seguida digitar e submeter esta mesma quantidade de instncias do problema
para o sistema e ainda depois conferir um a um os resultado obtidos com os
esperados. Enfim, um trabalho imenso. Imagine agora se fossem dois
parmetros? A quantidade de pares seria da ordem de 4.29497 x 10^09 (algo da
ordem de quatro bilhes). E para 3 parmetros? E para n parmetros? Nmeros
cada vez mais enormes. Por este caminho, testar programas seria invivel.
Felizmente no precisamos de todos eles, basta identificar as classes
distintas que importam para o problema, ou seja, as classes de equivalncia
relevantes. Isto pode ser obtido analisando o enunciado estendido do problema.
No caso de nosso exemplo anterior, analisando melhor a definio,
podemos identificar que por definio espao cartesiano se divide em quatro
regies. A primeira, onde ambos as coordenadas so positivas, denominamos de
primeiro quadrante. A segunda, onde a coordenada x negativa e a y positiva,
denominamos de segundo quadrante. O terceiro quadrante o espao onde
ambas as coordenadas so negativas. Ainda temos o quarto quadrante onde a
coordenada x positiva e a y negativa. E os pontos que ficam em um dos eixos
ou na interseo destes, qual a classificao que eles tm? Bom, podemos
convencionar que no esto em nenhum dos 4 quadrantes descritos. Resumindo,
nosso plano de teste deve contemplar estas situaes, conforme ilustra-se na
tabela a seguir.
x
positivo
negativo
negativo
negativo
nulo
qualquer
no nulo
nulo

y
quadrante
positivo
primeiro
positivo
segundo
negativo
terceiro
positivo
quarto
qualquer
eixo das ordenadas
no nulo
nulo

eixo das abscessos

nulo

origem

bom observar ainda que este plano pode e deve ser preparado antes
mesmo de elaborar o programa, para faz-lo, precisamos apenas da especificao
detalhada. Alm disso, este plano no precisa ser feito pelo programador
responsvel pela elaborao da soluo, qualquer outro programador, de posse
do enunciado detalhado, pode se encarregar da tarefa. Este tipo de plano serve
para alimentar o teste denominado de caixa preta. Esta denominao se deve ao
fato de no ser necessrio conhecermos a estrutura da soluo para elaborar o
plano. Um outro aspecto positivo da elaborao do plano o mais cedo possvel
que contribu para um melhor entendimento do problema.

6
2
Voltando ao nosso exemplo, podemos agora elaborar a nossa planilha de
teste considerando as classes de equivalncia a serem definidas. Uma questo
que surge como escolhemos o representante de uma classe? Existem melhores
e piores? No nosso caso, como pode ser qualquer valor positivo ou negativo,
podemos escolher valores de um dgito apenas, no mnimo escreveremos e
digitaremos menos.
x

2
-2
-2
2
0
0
2
-2
0

3
3
-3
-3
3
-3
0
0
0

resultado
esperado
True
False
False
False
False
False
False
False
False

resultado
obtido

diagnstico

8.4. REALIZANDO O TESTE: Vejamos agora o resultado de nossa interao com


o HUGS.
? primquad 2 3
True
? primquad (-2) 3
False
? primquad (-2) (-3)
False
? primquad 2 (-3)
False ?
primquad 0 (-3)
False
? primquad 0 3
True
? primquad 0 (-3)
False
? primquad 2 0
True
? primquad (-2) 0
False
? primquad 0 0
True
?

6
3
Voltemos agora para nossa planilha e vamos preench-la na coluna de resultado
obtido e diagnstico.
x
2
-2
-2
2
0
0
2
-2
0

resultado resultado
esperado obtido
3
True
True
3
False
False
-3
False
False
-3
False
False
3
False
True
-3 False
False
0
False
True
0
False
False
0
False
True
y

diagnstico
sucesso
sucesso
sucesso
sucesso
falha
sucesso
falha
sucesso
falha

8.5. Depurao: Uma vez testado o programa e identificado que ocorreram


instncias para as quais a nossa definio no est fazendo a associao correta,
ou seja, o valor obtido diferente do esperado, devemos passar a uma nova fase.
Depurar um programa um processo que consiste em buscar uma explicao
para os motivos da falha e posteriormente corrigi-la. Obviamente isto tambm no
um processo determinante e nem possumos uma frmula mgica. Ao longo de
nossa formao de programadores iremos aos poucos incorporando heursticas
que facilitem esta tarefa. Por enquanto muito cedo para falarmos mais do
assunto e vamos concluir com um fechamento do problema anterior. Aps concluir
as modificaes devemos testar o programa novamente.
Depurando nossa soluo - Podemos concluir por simples inspeo da
nossa ltima planilha (aquela com todas as colunas preenchidas) que nossa
soluo est incorreta. Uma interpretao dos resultados nos leva hiptese de
que a nossa soluo considera que quando o ponto se localiza na origem ou em
um dos eixos positivos, a nossa definio est considerando que eles esto no
primeiro quadrante.
Passo seguinte, verificar se de fato nossa definio incorre neste erro. Em
caso afirmativo, corrigi-la e a seguir resubmet-la aos testes.
Observando a nossa definio inicial, podemos concluir que de fato nossa
hiptese se confirma.
primquad x y

(x >= 0) && (y >= 0)

Podemos ento modific-la para obter uma nova definio, que esperamos
que esteja correta.

6
4
primquad x y

(x > 0) && (y > 0)

Agora submet-la novamente ao teste e ver o que acontece!


8.6. UMA SNTESE DO PROCESSO: O processo , como vimos, repetitivo e s
se encerra quando no identificarmos mais erros. O diagrama ilustra o processo
como um todo.
Mas lembre-se, isto ainda no garante que seu programa
esteja 100% correto! Quando no identificamos erro, apenas
podemos concluir que para as instncias que usamos o nosso
programa apresenta os resultados esperados.

6
5
9. RESOLVENDO PROBLEMAS - OS MOVIMENTOS DO CAVALO

9.1. INTRODUO: Considere o jogo de xadrez, onde peas so movimentadas


em um tabuleiro dividido em 8 linhas e oito colunas. Considere ainda os
movimentos do cavalo, a partir de uma dada posio, conforme diagrama a seguir,
onde cada possvel movimento designado por mi. No esquema, o cavalo
localizado na posio (5, 4) pode fazer oito movimentos, onde o primeiro deles,
m1, levaria o cavalo para a posio (7,5).
8 m3
7
6
5
4
3
2
1
1

m3

m3

m3

m3

m3

m3

m3

M3

m2

m4

m1
C

m5

m8
m6

m7
5

9.2. PROBLEMA 1: Escreva uma funo que determina se, a partir de uma dada
posio, o cavalo pode ou no realizar o primeiro movimento. Vamos cham-la de
pmov, e denominar seus parmetros (a posio corrente), de x e y. Eis alguns
exemplos de uso de nossa funo e os valores esperados:
instncia
pmov 5 4
pmov 8 1
pmov 1 1
pmov 1 8

resultado
True
False
True
False

9.2.1. Soluo - A SOLUO PODE SER ENCONTRADA ATRAVS DA


CONSTRUO DE UMA EXPRESSO BOOLEANA QUE AVALIE SE A NOVA
POSIO, OU SEJA, AQUELA EM QUE O CAVALO SERIA POSICIONADO
PELO PRIMEIRO MOVIMENTO, EST DENTRO DO TABULEIRO. COMO O
CAVALO, NO PRIMEIRO MOVIMENTO, ANDA DUAS CASAS PARA DIREITA E
UMA PARA CIMA, BASTA VERIFICAR SE AS COORDENADAS DA NOVA
POSIO NO ULTRAPASSAM A OITAVA FILEIRA (LINHA OU COLUNA).
Codificando em HUGS, temos ento:
pmov x y

= (x + 2 <= 8 ) && (y + 1 <= 8)

6
6
9.2.2. TESTANDO A SOLUO - Como j discutimos anteriormente, para
verificar a correo de nossa soluo, devemos submet-la a um teste. Para tanto
devemos escolher as classes de equivalncias relevantes e, a partir delas,
produzir a nossa planilha de teste. Olhando para a especificao do problema,
podemos identificar 4 conjuntos de valores que se equivalem para os fins do
nosso programa, como podemos observar na figura abaixo:
8
7
6
5
4
3
2
1
1

9.2.3. Estendendo o Problema - Podemos fazer o mesmo para todos os


demais movimentos, obtendo com isso as seguintes definies:
pmov x y
smov x y
tmov x y
qmov x y
qtmov x y
sxmov x y
stmov x y
omov x y

=
=
=
=
=
=
=
=

(x + 2 <= 8 ) && (y + 1 <= 8)


(x + 1 <= 8 ) && (y + 2 <= 8)
(x - 1 >= 1 ) && (y + 2 <= 8)
(x - 2 >= 1 ) && (y + 1 <= 8)
(x - 2 >=1 ) && (y - 1 >= 1)
(x - 1 >= 1 ) && (y - 2 >= 1)
(x + 1 <= 8 ) && (y - 2 >= 1)
(x + 2 <= 8 ) && (y - 1 >= 1)

9.2.4. Identificando Abstraes - Podemos agora indagar, olhando para as


oito definies, sobre a ocorrncia de algum conceito geral que permeie todas
elas. Poderamos tambm ter feito isso antes. Como no o fizemos, faamo-lo
agora. Podemos observar que todas elas avaliam duas expresses e que ambas
testam fronteiras que podem ser margem direita, margem esquerda, margem
superior ou margem inferior. Podemos observar ainda, que o par margem direita e
margem superior testam o mesmo valor 8, assim como ocorre com as duas outras,
que testam o valor 1. Com isso podemos definir duas novas funes, f e g, para
testar estes limites. Agora, as nossas definies anteriores podem ser reescritas,
usando as duas abstraes identificadas.
pmov x y
smov x y
tmov x y

=
=
=

f (x + 2 ) && f( y + 1)
f (x + 1) && f (y + 2)
g (x - 1) && f (y + 2)

6
7
qmov x y
qtmov x y
sxmov x y
stmov x y
omov x y
fw
gw

=
=
=
=
=
=
=

g (x - 2) && f (y + 1)
g (x - 2) && g (y 1)
g (x - 1) && g (y 2)
f (x + 1 ) && g (y 2)
f (x + 2) && g (y 1)
w <= 8
w >= 1

9.2.5. Anlise da Soluo - O que ser que ganhamos com esta nova forma
de descrever a nossa soluo? Podemos indicar pelo menos trs indcios de
vantagem na nova soluo:
1. Clareza - Na medida em que agora est explicitado, que todas as oito
funes para verificar os movimentos possuem estrutura semelhante e que
todas esto usando funes para verificar a ultrapassagem das bordas;
2. Manuteno - Se nosso tabuleiro mudasse, ou seja, passasse a ter 9 linhas
por nove colunas, bastaria alterar a funo f e tudo estaria modificado, ao
invs de termos que alterar as oito definies.
3. Reuso - As duas funes que testam as bordas poderiam ser usadas para
construir funes para avaliar o movimento de outras peas do jogo de
xadrez.
9.3. PROBLEMA 2: Sabemos que para cada posio alguns movimentos podem
ser realizados e outros no. Como ordenamos os movimentos no sentido antihorrio, gostaramos de obter, para uma dada posio, dos movimentos que
podem ser realizados, aquele que possui o menor ndice. Vejamos o esquema
abaixo.

8 m4
m1 m3 m3 C1
7
C3
m5
6 m5
m8
m6
5
m6
m7
4
3
m2
m3
2
m1
m4
1 C4
C2
1
2
3
4
5
6
7
8
Podemos observar que o cavalo C1 s pode fazer os movimentos m5 e m6
e que o de menor ndice m5. J o cavalo C2 s pode fazer os movimentos m3 e
m4 e que o de menor ndice o m3. Enquanto isso o cavalo C3 pode fazer os

6
8
movimentos m1, m4, m5, m6, m7 e m8. Para este caso o movimento de menor
ndice o m1.
Vamos chamar esta funo de qualmov e, como no problema anterior, os
parmetros sero as coordenadas da posio atual do cavalo. Eis alguns
exemplos de uso de nossa funo:

Instncia
qualmov 8 1
qualmov 8 8
qualmov 3 7
qualmov 1 1

resultado
3
5
1
1

9.3.1. SOLUO - Bem, como j sabemos, para verificar se um dado


movimento mi possvel, basta arranjar um meio de sair verificando um-a-um os
movimentos, a partir do primeiro (m1) e encontrar o primeiro que pode ser
realizado. Quando isso ocorrer podemos fornecer como resposta o seu ndice.
Podemos construir para isso uma rvore de deciso. Na raiz da rvore estar a
pergunta
" possvel realizar o movimento m1"?
Em caso afirmativo (brao esquerdo da rvore), mapeamos no valor 1 e em
caso negativo (brao direito), o que devemos fazer? Bom, a podemos comear
uma nova rvore (na verdade uma sub-rvore), cuja raiz ser:
" possvel realizar o movimento m2"?
E da prosseguimos at que todos os movimentos hajam sido considerados.
A rvore resultante ser:

6
9

9.3.2. CODIFICANDO A SOLUO - Vamos ento explorar os recursos da


linguagem para transformar nosso plano em um programa que de fato possa ser
"entendido" pelo nosso sistema de programao (HUGS). Como podemos
observar temos aqui o caso de uma funo que no contnua para o domnio do
problema. Pelo que sabemos at ento, no d para expressar a soluo como
uma nica expresso simples. Resta-nos o recurso das expresses condicionais.
Para verificar se um dado movimento satisfeito podemos usar as funes que
construmos anteriormente e com isso obtemos a seguinte definio:
qualmov x y

= if pmov x y then 1
else if smov x y then 2
else if tmov x y then 3
else if qmov x y then 4
else if qtmov x y then 5
else if sxmov x y then 6
else if stmov x y then 7
else if omov x y then 8
else 0

9.3.3. Anlise da Soluo - Em primeiro lugar, inclumos a resposta igual a


zero (0) quando o movimento m8, o ltimo a ser avaliado, resulta em fracasso.
Para que serve isso? Acontece que se a posio de entrada no for vlida, ou
seja, uma ou ambas as coordenadas no pertencerem ao intervalo [1, 8], nenhum
movimento seria vlido e se no providenciarmos uma resposta alternativa, nossa
funo seria parcial. Mas isto resolve de fato nosso problema? O que ocorreria se
a posio de entrada fosse (0, 0)? Bom, nossa funo determinaria que o primeiro
movimento poderia ser realizado e isto no verdade. A inveno de um resultado
extra para indicar que no h soluo possvel, transformando uma funo parcial
em uma funo total, parece ser boa, mas como foi feita no resolveu. Em geral o
melhor nestas situaes preceder toda e qualquer tentativa de determinar a
soluo adequada, por uma avaliao da validade dos dados de entrada. Neste

7
0
caso, bastaria verificar se os dois esto no intervalo [1, 8]. Vamos construir aqui
uma funo que avalia a pertinncia de um valor a um intervalo numrico,
conforme definio a seguir:
pert x a b

= (x >= a) && (x<=b)

Especulando um pouco mais sobre a nossa soluo, podemos observar


que o movimento m8, jamais ocorrer! Analisando os possveis movimentos
chegaremos concluso de que para nenhuma posio, o oitavo o nico
movimento possvel. Sugerimos fortemente que o leitor prove este teorema.
Portanto a soluo final pode ser:
qualmov x y

= if not (pert x 1 8)
|| not (pert y 1 8) then 0
else if pmov x y then 1
else if smov x y then 2
else if tmov x y then 3
else if qmov x y then 4
else if qtmov x y then 5
else if sxmov x y then 6
else 7

9.4. REVISITANDO O PROBLEMA 1: Observando a soluo encontrada para o


problema 1, constatamos que embora a noo de movimento do cavalo seja
nica, quem precisar saber se um dado movimento vlido, precisar conhecer o
nome das oito funes. Embora seja cedo para falarmos de interface homemmquina, j d para dizer que estamos sobrecarregando nosso usurio ao darmos
oito nomes para coisas to parecidas. Ser que temos como construir uma s
funo para tratar o problema? Vamos reproduzir aqui a interface das oito:
pmov x y
smov x y
tmov x y
qmov x y
qtmov x y
sxmov x y
stmov x y
omov x y

Propositadamente escrevemos o nome delas com um pedao em vermelho


e outro em preto. Seria alguma homenagem algum time que tem essas cores?

7
1
Na verdade estamos interessados em destacar que a pequena diferena nos
nomes sugere que temos uma mesma funo e que existe um parmetro oculto.
Que tal explicit-lo? Podemos agora ter uma funo com 3 parmetros, sendo o
primeiro deles para indicar o nmero do movimento que nos interessa. A interface
agora seria:
mov m x y
Agora, por exemplo, para solicitar a avaliao do stimo movimento para um
cavalo em (3, 4), escrevemos:
? mov 7 3 4
True
?
Muito bem, e como codificaremos isso?
9.4.1. SOLUO - Precisamos encampar em nossa soluo o fato de que a
nossa funo possui diferentes formas de avaliao, para diferentes valores do
domnio, algo parecido com a soluo do problema 2, ou seja, a nossa funo no
continua e portanto temos que selecionar qual a definio apropriada para um
determinado valor de m. Devemos construir uma rvore de deciso. Aqui
deixamos esta tarefa a cargo do leitor e passamos direto codificao conforme
apresentamos a seguir:
mov m x y

= if not (pert m 1 8)
False
else if m == 1 then
else if m == 2 then
else if m == 3 then
else if m == 4 then
else if m == 5 then
else if m == 6 then
else if m == 7 then
else omov
where
pmov = ...
smov = ...
tmov = ...
...

then
pmov
smov
tmov
qmov
qtmov
sxmov
stmov

9.4.2. Anlise da soluo - Ao contrrio da soluo do problema 2, onde


necessariamente a validade dos movimentos tinha que ser verificada do primeiro
para o ltimo, pois nos interessava saber qual o primeiro possvel de ser realizado,
o leitor pode observar que esta ordem aqui no necessria. Tanto faz se
perguntamos primeiro se m=7 ou se m=3. Ser que podemos tirar algum proveito
disso? Alertamos o iniciante, que devemos sempre identificar propriedades

7
2
internas do problema e explor-las adequadamente. Qual a influncia desta ordem
na eficincia da avaliao de uma expresso submetida ao HUGS? Para
responder, basta lembrar que as condies so avaliadas seqencialmente. Por
exemplo, se m=8, teremos que avaliar 8 condies, se m=1 faremos 2 avaliaes
e se m est fora do domnio faremos uma avaliao. Ou seja, no pior caso
faremos 8 avaliaes e no melhor caso uma (1). Em mdia, ao longo do uso da
funo, assumindo uma distribuio uniforme dos valores de m, faremos 4
avaliaes. E se o intervalo fosse de 100 elementos distintos, quantas avaliaes
de condies faramos em mdia? Ser possvel elaborar solues onde este
nmero de avaliaes seja menor?
A resposta sim! J que a ordem das avaliaes no importa, podemos
buscar uma ordem mais conveniente para reduzir o nmero de avaliaes por
cada instncia avaliada.
A idia geral para estes casos obtida a partir de um conceito de vasta
utilidade na Computao. Falamos de rvore binria e o leitor por certo ouvir
falar muito dela ao longo da vida enquanto profissional da rea.
O caminho consiste em dividir intervalo considerado ao meio e fazer a
primeira pergunta, por exemplo, m<=4? Dividindo em 2 o intervalo de
comparaes, para cada um destes podemos novamente dividir ao meio, at que
no mais tenhamos o que dividir, como ilustramos no diagrama a seguir, onde
cada linha representa um passo da diviso dos intervalos.
<1
<1
<1

1
1
1

2
2
2

3
3
3

4
4
4

Que tambm podemos representar por:

5
5
5

6
6
6

7
7
7

8
8
8

>8
>8
>8

7
3
A codificao ficar ento:
mov m x y = if not (pert m 1 8)
then False
else if m <= 4
then if m<= 2
then if m== 1
then pmov
else smov
else if m==3
then tmov
else qmov
else if m<= 6
then if m==5
then qtmov
else sxmov
else if m == 7
then stmov
else omov
where
pmov = ...
smov = ...
tmov = ...
...

Se fizermos uma anlise das possibilidades veremos que para qualquer


valor de m o nmero mximo de avaliaes que faremos ser sempre igual a
quatro! E se fosse 100 valores para m, qual seria o nmero mximo de
comparaes? E para 1000? E 1000000?
O nmero de comparaes, seguindo este esquema, aproximadamente
igual ao logaritmo do nmero de valores na base 2. Portanto para 100 teramos 7,
para 1000 teramos 10 e para um milho teramos 20. Veja que bem inferior ao
que obtemos com o esquema anterior, tambm denominado de linear. Confira a
comparao na tabela abaixo.
nmero de
valores
8
100
1000
1000000

esquema linear
(nmero mdio)
8
50
500
500000

esquema binrio
(nmero mximo)
4
7
10
20

7
4
10. TUPLAS
10.1. INTRODUO: At ento trabalhamos com valores elementares. Ou seja,
valores atmicos, indivisveis a nvel das operaes de seu tipo de dados. Por
exemplo, True, 523, 8.234, so valores elementares dos tipos Boolean, Integer e
Float, respectivamente. No podemos, por exemplo, nos referir, dentro da
linguagem, ao primeiro algarismo do valor 523. Dizemos que esses so tipos
primitivos da linguagem. Alm desses trs, o Hugs prov ainda o tipo char. O
elenco de tipos primitivos de uma linguagem pode ser entendido como o alicerce
da linguagem para a descrio de valores mais complexos, que so denominados
genericamente de valores estruturados.
Os problemas que pretendemos resolver esto em universos mais ricos em
abstraes do que esse das linguagens. Para descrever esses mundos,
precisamos usar abstraes apropriadas para simplificar nosso discurso. Por
exemplo, quando quero saber onde algum mora, eu pergunto: Qual o seu
endereo? Quando quero saber quando um amigo nasceu, eu pergunto: Qual a
data do seu nascimento? E quando quero saber para onde algum vai deslocar o
cavalo no jogo de xadrez, eu pergunto: Qual a nova posio? Os nomes
endereo, data e posio designam valores estruturados. Uma data tem trs
partes: dia, ms e ano. Um endereo pode ter quatro: rua, nmero, complemento
e bairro. J a posio no tabuleiro tem duas partes, linha e coluna.
Para possibilitar a descrio de valores dessa natureza, o Hugs dispe de
um construtor denominado tupla. Podemos definir uma tupla como um agregado
de dados, que possui quantidade pr-estabelecida de componentes (dois ou
mais), e onde cada componente da tupla pode ser de um tipo diferente (primitivo
ou no).
10.2. DEFINIO DO CONCEITO: A representao de uma tupla feita com a
seguinte sintaxe:
(t1, t2, t3, ..., tn)
Onde cada ti um termo da tupla.
Se Ti o tipo de ti, ento o universo de uma tupla dado por:
TT = T1 x T2 x ... x Tn
Sabendo-se que os conjuntos bases dos tipos Ti so ordenados, tambm os
elementos de TT o sero.

7
5
Exemplos de Tuplas:

1
2

Inteno
uma data
uma posio no
tabuleiro de xadrez

uma pessoa

4
5
6
7

um ponto no espao
uma carta de baralho

Representao
(15, 05, 2000)
(3, 8)
("Maria Aparecida", "solteira",
(3, 02, 1970))
(3.0, 5.2, 34.5)
(7, "espada")
(True, 3)
(False, div 5 2)

(x/=0 && y /= 0,
(x > y, if x*y /= 0
8

then if x > y
then div x y
else div y x
else 0)

(x, y, x + y)

10.3. COMPONDO TUPLAS: Os exemplos apresentados j parecem suficientes


para que tenhamos entendido como descrever um valor do tipo tupla. Vamos
ento apenas comentar sobre os exemplos e ilustrar o uso de tuplas nas
definies.
Uma tupla um valor composto. Isto significa que devemos colocar entre
parntesis e separados por vrgulas os componentes deste valor. Cada
componente um valor, descrito diretamente ou atravs de expresses
envolvendo operadores. Nos exemplos de 1 a 7, todos eles usam constantes. O
exemplo 7 apresenta um dos valores descrito por uma expresso. No exemplo 3,
um dos termos uma outra tupla. Qualquer termo pode ser uma tupla. Um valor
pode tambm ser paramtrico, como no exemplo 9, onde temos uma tupla de 3
termos, todos eles paramtricos, mas o terceiro depende dos dois primeiros.
Podemos dizer que esta tupla descreve todas as triplas onde o terceiro termo
pode ser obtido pela soma dos dois primeiros. No exemplo 8 podemos observar o
uso de expresses condicionais. Observa-se a tambm a descrio de um termo
do tipo boolean, atravs de uma expresso relacional combinada com operadores
lgicos.
Vejamos agora alguns exemplos de uso de tuplas na descrio de valores.
Exemplo 1: Desejamos definir uma funo, para que dados 2 valores, seja
produzido uma tripla onde os dois primeiros termos so idnticos aos elementos
fornecidos, em ordem inversa, e o terceiro termo seja igual soma dos dois.

7
6
triplaS a b = ( b, a, a + b )

Exemplo 2: Vamos definir uma funo que produza o quociente e o resto da


diviso inteira de dois nmeros.
divInt a b = ( q, r)
where
q = div a b
r = rem a b

Exemplo 3: Voltemos definio das razes de uma equao do 2o. grau.


Vimos anteriormente que como eram duas, precisvamos definir tambm duas
funes. Agora podemos agrup-las em uma nica definio:
re2g a b c = ( x1, x2)
where
x1
x2
e
duploA

= ((-b) + e)/ duploA


= ((-b) - e)/ duploA
= sqrt (b^2 - 4.0*a*c)
= 2.0 * a

7
7
Exemplo 4: Voltemos aos movimentos do cavalo no jogo de xadrez. Vamos
definir uma funo que produza a nova posio, usando o primeiro movimento
vlido segundo o que se discutiu em Resolvendo Problemas - Os Movimentos do
Cavalo.
qPos x y = if f x2 && f y1
then (x2,y1)
else if f x1 && f y2
then (x1,y2)
else if g x1e && f y2
then (x1e,y2)
else if g x2e && f y1
then (x2e,y1)
else if g x2e && g y1e
then (x2e,y1e)
else if g x1e && g y2e
then (x1e,y2e)
else if f x1 && f y2e
then (x1,y2e)
else (0,0)
where
x1
= x + 1
x2
= x + 2
y1
= y + 1
y2
= y + 2
x1e
= x - 1
x2e
= x - 2
y1e
= y - 1
y2e
= y - 2
f w
= w <= 8
g w
= w >= 1

Qual o valor de qPos 1 9 ? O que h de errado? Reescreva qPos de forma


a contornar o problema encontrado.
10.4. SELECIONANDO TERMOS DE UMA TUPLA: Assim com precisamos
compor uma tupla na descrio dos mapeamentos de uma funo, tambm
precisamos decomp-la. Quando uma funo possui tuplas como parmetros,
para usar seus termos necessrio que se possa referenci-los..
Ilustraremos aqui vrias formas, utilizando a definio que soluciona o
seguinte problema:
Desejamos determinar a distncia entre dois pontos no plano.
1. Utilizando a clusula where :
dist p1 p2 = sqrt (dx^2 + dy^2)
where
dx
= x1 - x2
dy
= y1 - y2
(x1,y1) = p1
(x2,y2) = p2

7
8
Observe
a
elegncia
da
definio
da
tupla
(x1,
y1)!
Por anlise da definio, sabemos que o tipo de p1 e p2 tupla de 2 termos.
Quando submetemos a avaliao de uma instncia, o sistema casa p1 com um
par de valores e a partir da pode determinar o valor de cada termo de nossa tupla
(x1, y1).
? dist (0.0,0.0) (5.0,5.0)
-- o sistema casa p1 com (0.0,0.0)
-- e p2 com (5.0,5.0)
-- logo x1=0.0, y1=0.0, x2=5.0 e y2=5.0
7.07107

2. Construindo funes seletoras :


prim (x,y) = x
seg (x,y) = y
dist p1 p2 = sqrt (dx^2 + dy^2)
where
dx
= prim p1 - prim p2
dy
= seg p1 - seg p2

Com esta abordagem, podemos generalizar e construir funes seletoras


para tuplas com uma quantidade de termos qualquer. importante destacar que
tuplas com quantidade diferente de termos precisam ter o seu prprio elenco de
funes seletoras.
Em particular, para o caso acima, onde o nmero de termos 2, o prprio
HUGS j possui as funes seletoras, fst (primeiro) e snd (segundo). Poderamos
t-las usado diretamente, mas preferimos ilustrar como se constri. Podemos
reescrever a soluo usando-as.
dist p1 p2 = sqrt (dx^2 + dy^2)
where
dx
= fst p1 - fst p2
dy
= snd p1 - snd p2

3. Explicitando os componentes:
dist (x1,y1) (x2,y2) = sqrt (dx^2 + dy^2)
where
dx
= x1 - x2
dy
= y1 - y2

7
9
11. VALIDAO DE DADOS
11.1. INTRODUO: Como sabemos, toda funo tem um domnio e um
contradomnio. Em Hugs, quando tentamos avaliar uma instncia de uma
definio, usando valores fora desse domnio, podemos receber como resposta
mensagens nem sempre esclarecedoras. Quando se trata do usurio de nosso
programa, esta situao se mostra mais indesejvel ainda. Aqueles que
constroem a definio podem discernir com mais facilidade a natureza dos
problemas que ocorrem durante o seu desenvolvimento. O mesmo no se pode
esperar de algum que no tem conhecimento dos elementos internos de nossas
definies.
Tipicamente os erros sero de duas naturezas. Pode ser que o tipo da
instncia esteja correto mas nossa definio use alguma funo primitiva que no
se aplica ao valor da instncia. Por exemplo, se temos a definio:
f x y z = div x y + z

e se a submetemos a uma instncia onde y = 0, teremos como resultado algo da


seguinte natureza:
? f 5 0 3
Program error: {5 `div` 0}
?

Um outro tipo de problema ocorre quando o tipo de algum parmetro da


nossa instncia no casa com o tipo inferido pelo Hugs. Por exemplo, se usamos
um valor do tipo Float para y, obtemos:
? f 5 1.0 3
ERROR: Type error in
application
*** expression
:
*** term
:
*** type
:
*** does not match :

f 5 1.0 3
1.0
Float
Int

Nesta seo trataremos do primeiro caso, deixando o segundo para outra


oportunidade.

8
0
11.2. CARACTERIZANDO A SITUAO - Voltemos definio anteriormente
apresentada:

f x y z = div x y + z

Neste caso, o tipo inferido pela linguagem para os dois primeiros parmetros
o tipo Integer, visto que o operador div s se aplica a valores deste tipo.
Portanto o universo ser formado por todos os possveis ternos de valores onde
os dois primeiros so do tipo Integer e o ltimo, do tipo obtido pela unio dos tipos
Float e Integer. Chamemo-lo de T. Entretanto, o domnio de nossa funo no
exatamente o conjunto de constantes de T, posto que a funo no est definida
para as constantes de T cujo segundo elemento nulo.

Desejamos construir uma funo que seja uma extenso da funo original e
ao mesmo tempo lhe sirva como uma casca de proteo contra as violaes de
domnio. Precisamos escolher um contradomnio da funo estendida (fx). Um
candidato natural o contradomnio da funo original (f).
E a imagem de nossa funo, o que podemos dizer dela? Ser que ela
igual ao contradomnio? Ou ser que temos um subconjunto para o qual no
exista um mapeamento?
11.3. CASO GERAL (IMAGEM IDNTICA AO CONTRADOMNIO): No caso
geral, podemos encontrar duas situaes: ou o contradomnio idntico
imagem, ou a determinao dos elementos que no pertencem imagem pode
no ser fcil. Com isto no dispomos de valores no contradomnio que possam ser
utilizados para mapearmos os valores que violam o domnio de f. Neste caso
podemos estender o contradomnio (CD) de tal modo que o novo escolhido
incorpore um valor que ser a imagem da extenso de f.
Uma soluo geral bastante conveniente construir um novo contradomnio
(NCD) para fx (extenso de f), formado por pares onde o primeiro elemento do
tipo boolean e o segundo do contradomnio de f. Temos ento a seguinte
estrutura:

8
1
NCD(fx) = (boolean, CD(f))
Para valores de x no domnio de f, teremos:
fx x = (True, fx )
Para os valores de x fora do domnio teremos:
fx x = (False, k )
onde k um valor qualquer pertencente ao contradomnio de f.
Para o nosso exemplo inicial teramos ento:
fx x y z = if invalido x y z
then (False,0)
else (True, f x y z)
where
invalido x y z = ...
f x y z = div x y + z

como se estivssemos criando uma casca protetora para a f.


11.4. FUNES QUE APRESENTAM PROBLEMAS EM VRIOS
PARMETROS: Quando uma funo possui vrios parmetros, pode ocorrer que
mais de um deles dem origem questo que aqui levantamos. Quando isso
ocorre, pode ser relevante caracterizar a situao apropriadamente. Neste caso
podemos usar um conjunto de constantes mais variado do que as constantes
booleanas, permitindo que possamos associar com cada erro uma constante
diferente.
Podemos tomar como exemplo o problema do movimento dos cavalos no
jogo de xadrez, especificamente a soluo genrica que produzimos com a funo
mov m x y
onde m o nmero do movimento, x a linha atual e y a coluna atual.
Os trs parmetros so vlidos apenas para o intervalo [1, 8]. Portanto mov
no est definida para os valores pertencentes ao subconjunto do universo
formado por todas as triplas onde pelo menos um dos elementos no pertence ao
intervalo [1, 8]. Por outro lado, o contradomnio conjunto booleano e portanto s
possui 2 constantes, e ambas j esto comprometidas. Se quisermos distinguir os
3 tipos de violaes do domnio (movimento invlido, posio invlida, ambos
invlidos) precisaremos usar um conjunto com pelo menos 4 constantes.

8
2
Podemos ento definir a funo movx da seguinte forma:
movx m x y = if not validom
then if not validop
then (3, False)
else (1, False)
else if not validop
then (2, False)
else (0, mov m x y)

11.5. CASO PARTICULAR (IMAGEM DIFERENTE DO CONTRADOMNIO):


Suponha que existe pelo menos um elemento k que no pertence imagem, ou
seja, a imagem est contida no contradomnio. Podemos construir uma extenso
de f de tal forma que os elementos que no pertenam ao domnio sejam
mapeados neste k e os demais sejam mapeados diretamente pela f . Quando
existe tal k, nosso problema est resolvido. Basta que o usurio saiba que,
quando a avaliao resultar em k, significa que a funo no se aplica para aquela
instncia.
Voltemos funo f introduzida anteriormente. Podemos, usando a proposta
desta seo reescrever a sua definio, da seguinte forma:
fx x y z = if invalido x y z
then k
else f x y z
where
k = ...
invalido x y z = ...
f x y z = div x y + z

Infelizmente, para esse caso, o k no existe (prove!).


Voltemos ao movimento do cavalo. Nesse caso, especificamente, porque o
contradomnio original o conjunto booleano, poderamos ter tomado outro
caminho. Poderamos usar nmeros negativos para indicar os 3 tipos de violao
do domnio, o 0 para representar False e o 1 para representar True, eliminando
com isso a necessidade de termos um novo domnio formado por pares. Vejamos
como fica esta definio:
movx m x y = if not validom
then if not validop
then (-3)
else (-1)
else if not validop
then (-2)
else if mov m x y then 1 else 0

8
3
11.6. UM EXEMPLO - RAIZES DE UMA EQUAO DO 2O. GRAU: Voltemos ao
problema de determinar as razes de uma equao do segundo grau. J sabemos
que elas so duas e que podemos fazer uma nica funo para descrev-las,
usando tupla.
Sabemos ainda que o universo definido pelos tipos dos 3 parmetros (a, b,
c), maior que o domnio da funo. Ou seja, a funo no est definida para
instncias de a, b e c, onde se verifica a seguinte desigualdade:
(b ^ 2) + (4 * a * c) < 0

Precisamos, portanto de uma funo estendida.


re2gx a b c = (not (delta < 0), if
delta < 0
then
(0,0)
else
(x1, x2))
where
delta = (b ^ 2) +
(4 * a * c)
x1
= ((-b) +
sqrt delta) / (2 * a)
x2
= ((-b) sqrt delta) / (2 * a)

Ou, de outra forma:


re2gx a b c = if delta < 0
then (False, (0, 0))
else (True, (x1, x2))
where
delta = (b ^ 2) +
(4 * a * c)
x1
= ((-b) +
sqrt delta) / (2 * a)
x2
= ((-b) sqrt delta) / (2 * a)

11.7. Exerccios
1. Explique por que no existe o valor k que apie a definio da funo fx;
2. Jpojpoj
3. Pojpoj
4. Pojpoij

8
4
12. LISTAS
12.1. INTRODUO: A maioria dos itens de informao de nosso interesse esto
agrupados, dando origem a um conceito muito importante para a resoluo de
problemas, o agrupamento. Freqentemente estamos interessados em manipular
esses agrupamentos para extrair informaes, definir novos itens ou avaliar
propriedades desses agrupamentos.
Tratamos anteriormente das tuplas, que so agrupamentos de tamanho
predefinido e heterogneo, ou seja, cada elemento que participa do agrupamento
pode ser de um tipo diferente. Agora estamos interessados em explorar um outro
tipo de agregao, as listas. Este novo tipo, em HUGS, caracteriza-se por agregar
quantidades variveis de elementos desde que todos eles sejam de um mesmo
tipo.
Vivemos cercados de listas. Elas esto em qualquer lugar onde precisamos
registrar e processar dados. Vejamos alguns exemplos:
1. Lista de nmeros pares;
2. Lista dos livros lidos por uma pessoa;
3. Lista dos amigos que aniversariam em um dado ms;
4. Lista dos presidentes corruptos;
5. Lista dos vereadores decentes;
6. Lista das farmcias enganadoras;
7. Lista das disciplinas que j cursei;
8. Lista dos Lugares que visitei;
9. Lista dos nmeros feios;
10. Lista dos nmeros primos;
11. Lista das posies para as quais um cavalo pode se deslocar;
12. Lista das palavras de um texto;
13. Lista dos bug provocados pelo Windows;
14. Lista dos prmios Nobel ganhos pelo Bertrand Russel.;
15. Lista dos ttulos conquistados pelo Nacional Futebol Clube;
16. Listas dos funks compostos pelo Noel Rosa.
Destas, algumas so vazias, outras so finitas e algumas infinitas.
12.2. CONCEITOS BSICOS: Uma lista uma seqncia de zero ou mais
elementos de um mesmo tipo.
Entende-se por seqncia uma quantidade qualquer de itens dispostos
linearmente.
Podemos representar uma lista pela enumerao dos seus elementos,
separados por vrgulas e cercados por colchetes.
[ e1, e2, .., en]

8
5
Por exemplo:
1.
2.
3.
4.
5.

[]
[1,3,5,7,9]
['a', 'e', 'i', 'o', 'u']
[(22,04,1500), (07,09,1822), (31,03,1964)]
[[1,2,5,10], [1,11], [1,2,3,4,6,12], [1,13], [1,2,7,14], [1,3,5,15]]

importante ressaltar que em uma lista podemos falar do primeiro elemento,


do quinto, do ensino, ou do ltimo. Ou seja, h uma correspondncia direta entre
os nmeros naturais e a posio dos elementos de uma lista.
Este ltimo fato nos lembra de um equvoco freqente, que queremos
esclarecer de sada. A ordem que se adota em listas, por ser baseada nos
nmeros naturais, comea do zero. Ou seja, o primeiro elemento de uma lista tem
o nmero de ordem igual a zero.
Por exemplo, na relao acima apresentada, a primeira lista vazia. Na lista
do item 4 o elemento de ordem 1 a tupla (07, 09,1822) e na lista do item 5, o
elemento de ordem zero (0) a lista [1,2,5,10].
Quanto ao tipo, podemos dizer que a segunda lista uma lista de nmeros, a
terceira uma lista de caracteres, a quarta uma lista de triplas de nmeros e a
quinta uma lista de listas de nmeros. Qual ser o tipo da primeira lista?
Uma lista vazia de natureza polimrfica, isto , seu tipo depende do
contexto em que seja utilizada, como veremos em momento oportuno.
12.3. FORMAS ALTERNATIVAS PARA DEFINIO DE LISTAS: Alm da forma
bsica, acima apresentada, tambm conhecida como enumerao, onde
explicitamos todos os elementos, dispomos ainda das seguintes maneiras:
definio por intervalo, definio por progresso aritmtica e definio por
compreenso. As duas primeiras formas apresentamos a seguir a terceira
posteriormente.
Definio por Intervalo
De uma forma geral, podemos definir uma lista explicitando os limites inferior
e superior de um conjunto conhecido, onde existe uma relao de ordem entre os
elementos, no seguinte formato:
[<limite inferior> .. <limite superior>]

8
6
Exemplos: abaixo listamos algumas submisses de listas definidas por intervalo e
as correspondentes respostas do sistema HUGS.
1 Prelude> [1..5]
[1,2,3,4,5]
2 Prelude> [-2..2]
[-2,-1,0,1,2]
3 Prelude> [10..5]
[]
4 Prelude> [-5.0..5.0]
[-5.0,-4.0,-3.0,-2.0,-1.0,0.0,1.0,2.0,3.0,4.0,5.0]
5 Prelude> [-1..-5]
ERROR: Undefined variable "..-"
6 Prelude> [-1..(-5)]
[]
7 Prelude> [1.6..10.0]
[1.6,2.6,3.6,4.6,5.6,6.6,7.6,8.6,9.6]
8 Prelude> [1.5..10.0]
[1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5]

Podemos observar aqui algumas aparentes surpresas: na definio 4 podemos


observar que o HUGS considera sempre o intervalo de uma unidade entre os
elementos da lista definida. Na definio 5, temos uma questo de ambigidade, 0
sinal de menos logo aps os dois pontos no entendido e o sistema sinaliza
erro. A definio 6 contorna essa dificuldade. Deixo ao leitor buscar explicao
para o que ocorre com as definies 7 e 8.
Definio por Progresso Aritmtica
Podemos definir qualquer progresso aritmtica por uma lista utilizando a seguinte
notao:
[<1o. termo>, <2o. termo> .. <limite superior>]
Exemplos: observemos as definies a seguir e as respectivas respostas do
sistema HUGS. Podemos perceber que dependendo do segundo termo da
definio o sistema interpreta a P.A. como crescente ou decrescente.
1 Prelude> [1,2..6]
[1,2,3,4,5,6]
2 Prelude> [-5,2..5]
[-5,2]
3 Prelude> [-5,2..15]
[-5,2,9]
4 Prelude> [-5,2..16]
[-5,2,9,16]
5 Prelude> [1,1.1 .. 2]
[1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0]
6 Prelude> [6,5..0]
[6,5,4,3,2,1,0]
7 Prelude> [5,6..5]

8
7
[5]
8 Prelude> [3,7..1]
[]

12.4. OPERAES BSICAS: As listas, como j dissemos, so elementos da


linguagem que podemos utilizar para descrever valores estruturados. Como nos
demais tipos da linguagem, valores descritos por listas podem e devem ser
usados na descrio de novos valores atravs da utilizao de operaes
definidas sobre eles. A seguir so apresentadas algumas dessas operaes.
elem : avalia se um determinado elemento membro de uma lista.
elem <elemento> <lista>
Exemplos:
Main>
True
Main>
False
Main>
False
Main>
True

elem 5 [-5..15]
elem (-10) [-5..15]
elem 20 [-5..15]
elem 15 [-5..15]

length : descreve o tamanho de uma lista.


length <lista>
Exemplos:
Prelude>length [1..100]
100
(2528 reductions, 3442 cells)
Prelude>length [1..100] + length [1..100]
200
(5050 reductions, 6873 cells)
Prelude> a + a where a = length [1..100]
200
(2530 reductions, 3442 cells)

indexao : podemos descrever como um novo valor, cada termo de uma


lista. Para tanto basta indicarmos a posio do elemento dentro da lista,
considerando que o primeiro elemento tem a ordem zero.
<lista>!!<ndice>
Exemplos:

8
8
1 Prelude> [3,4,6,74,45]!!0
3
2 Prelude> [3,4,6,74,45]!!4
45
3 Prelude> [1,5..20]!!3
13
4 Prelude> [[[1],[2,3,4]]]!!0!!1!!2
4
5 Prelude> [3,4,6,74,45]!!3
74
6 Prelude> [3,4,6,74,45]!!3 + [2,3]!!0
76
7 Prelude> [3,4,6,74,45]!!(0+1)
4
8 Prelude> [3,4,6,74,45]!!(i+j) where i=3; j=0
74
9 Prelude> [84,76,23,124,763,23]!!([0,1,2,3]!!2)
23
10 Prelude> [1,5..20]!!5
Program error: Prelude.!!: index too large

concat : descreve uma nova lista obtida pela concatenao de uma lista de
listas.
concat <lista de listas>
Exemplos:
1 Prelude>concat [[1..5],[1,10..100],[9]]
[1,2,3,4,5,1,10,19,28,37,46,55,64,73,82,91,100,9]
(473 reductions, 747 cells)
2 Prelude>concat [[1]]
[1]
(25 reductions, 35 cells)
3 Prelude> length (concat [[1..5],[1,10..100],[9]])
18
(451 reductions, 638 cells)
4 Prelude> concat [[length [10,87..500]], [length
[10,87,500]]]
[7,3]
(228 reductions, 309 cells)
5 Prelude> length (concat [[length [10,87..500]],
[length
[10,87,500]]])
2
(30 reductions, 35 cells)

Pode tambm ser usado com a sintaxe infixada usando o operador ++


Exemplos:

8
9
1 Prelude> [1] ++ [1]
[1,1]
(33 reductions, 48 cells)
2 Prelude> [1] ++ []
[1]
(23 reductions, 33 cells)
3 Prelude> [ ] ++ [ ]
ERROR: Cannot find "show" function for:
*** Expression : [] ++ []
*** Of type
: [a]
4 Prelude> [1..5] ++ [1,10..100] ++ [9]
[1,2,3,4,5,1,10,19,28,37,46,55,64,73,82,91,100,9]
(467 reductions, 738 cells)

construtor : descreve uma nova lista onde o primeiro termo um dado


elemento e os demais so os componentes de uma lista tambm dada..
<elemento> : <lista>
Exemplos:
1 Prelude> 3: [4,5,6]
[3,4,5,6]
2 Prelude> [3]:[[4,5,6]]
[[3],[4,5,6]]
3 Prelude> [3: [4,5,6]]
[[3,4,5,6]]
4 Prelude> [3: [4,5,6]]!!0
[3,4,5,6]
5 Prelude> [3: [4,5,6]]!!0!!3
6

head : descreve o primeiro elemento de uma lista..


tail : descreve uma sublista contendo todos os elementos, exceto o primeiro
elemento de uma lista dada.

Teorema importante:
head xs : (tail xs) = xs

last : descreve o ltimo elemento de uma lista..


init : descreve uma sublista contendo todos os elementos, exceto o ltimo
elemento de uma lista dada.

9
0
Teorema importante:

init xs ++ [last xs] = xs


Importante: As funes head, last, init e tail no possuem em seu domnio a
lista vazia. Portanto ela no deve ser instncia de avaliao para qualquer uma
delas.
<elemento> : <lista>
Exemplos:
1 Hugs> head [1,2,3,4,5,6]
1
2 Hugs> tail [1,2,3,4,5,6]
[2,3,4,5,6]
3 Hugs> tail [1,2,3,4,5,6]
[2,3,4,5,6]
4 Hugs> last [1,2,3,4,5,6]
6
5 Hugs> init [1,2,3,4,5,6]
[1,2,3,4,5]
6 Hugs> x == (head x : tail x) where x = [10..15]
True
7 Hugs> init [10..15] ++ tail [10..15]
[10,11,12,13,14,11,12,13,14,15]

12.5. DEFINIO POR COMPREENSO: Uma lista pode ser descrita


atravs da enumerao de seus elementos, como j vimos atravs de vrios
exemplos. Esta forma tambm denominada de definio por extenso, visto que
todos os componentes precisam ser explicitados.
Podemos tambm descrever listas atravs das condies que um elemento
deve satisfazer para pertencer a ela. Em outras palavras, queremos descrever
uma lista atravs de uma inteno. Esta forma anloga que j conhecemos
para descrio de conjuntos. Por exemplo, usual escrever a notao abaixo para
descrever o conjunto formado pelo quadrado dos nmeros naturais menores que
10.
P = { quadrado de x | x natural e menor que 10}
ou ainda mais formalmente,
P = { x2 | x pertence a N e x <10}
Podemos observar, no lado direito da definio, que ela formada por duas
partes. A primeira uma expresso que descreve os elementos, usando para isso

9
1
termos variveis que satisfazem condies de pertinncia estabelecidas pela
segunda parte.
expresso
varivel
pertinncia

x^2
x
x pertence a N e x <10

Em nosso caso, no estamos interessados em descrever conjuntos e sim


listas. E isso tem algumas implicaes prticas. Por exemplo, em um conjunto a
ordem dos elementos irrelevante, para listas no. bom lembrar ainda que em
uma lista, o mesmo valor pode ocorrer varias vezes, em diferentes posies.
A sintaxe que usaremos a seguinte:
[ <expresso> | <pertinncia> ]
Onde:
<expresso> - expresses usuais em Hugs para definio de valores, inclusive
condicionais.
<pertinncia> - descrio dos elementos a serem considerados para avaliao da
<expresso>
A pertinncia formada por uma seqncia de qualificadores de dois tipos
de construes: os geradores e os predicativos. Os geradores descrevem uma
lista de onde se originam os elementos a serem considerados, usando a sintaxe:
<termo> <- <lista>
Por exemplo, vejamos a descrio da lista dos quadrados dos nmeros
menores que 5.
Prelude> [x^2| x<-[0..4]]
[0,1,4,9,16]

Os predicativos so expresses descrevendo valores booleanos, envolvendo


termos j definidos anteriormente (inclusive por geradores).
Vejamos o exemplo a seguir, onde descrevemos uma sublista de nmeros
mpares, tendo como origem de gerao uma lista definida por uma Progresso
Aritmtica.
Prelude> [x | x<-[1,4..100],odd x]
[1,7,13,19,25,31,37,43,49,55,61,67,73,79,85,91,97]

importante destacar que as expresses de pertinncia so avaliadas da


esquerda para direita.

9
2
Por exemplo, se na expresso acima, primeiro colocssemos a expresso
booleana "odd x", o sistema acusaria um erro, visto que ao tentar a avaliar "odd x",
a varivel "x" ainda no estaria definida.
Prelude> [x | odd x, x<-[1,4..100]]
ERROR: Undefined variable "x"

Isto s ocorre porque o sistema usa uma ordem pr-definida!


Vejamos como usar este novo conceito na escrita de novos scripts. A seguir
apresentamos a definio de trs novas funes. A primeira, slpares, define uma
sublista formada pelos quadrados dos elementos pares de uma lista dada. A
segunda, lmenor, define uma sublista formada pelos elementos de uma dada
lista, que so menores que um elemento fornecido. A terceira, pmaioresk, ilustra
o uso da clusula if-then-else para a gerao de elementos de uma lista.

-- Dada uma lista 'xs' defina uma sublista formada


-- pelo quadrado dos elementos que so pares
-slpares xs = [x^2 | x<- xs, even x]
Main> :l preparalista.txt
Reading file "preparalista.txt":
Hugs session for:
E:\HUGS98\lib\Prelude.hs
preparalista.txt
Main> slpares [1,4..50]
[16,100,256,484,784,1156,1600,2116]
Main> slpares
[1156,144]

[34,67,99,23,12,3,67,99]

--- Determinar a sublista de elementos menores que 'x'


-- em uma lista 'xs
-lmenor x xs = [ y | y <-xs, y < x]
...
Main> lmenor 45 [1,5,6,86,34,76,12,34,86,99]
[1,5,6,34,12,34]
Main> lmenor 1 [1,5,6,86,34,76,12,34,86,99]
[]

9
3
Main> lmenor 100 [1,5,6,86,34,76,12,34,86,99]
[1,5,6,86,34,76,12,34,86,99]

--- Determinar a lista de elementos gerados condicionalmente


a uma
-- constante dada k.
pmenoresk k xs = [ if x > k then x2 else x + 2 | x <-xs]
...
Main> pmenoresk 30 [1,5,6,86,34,76,12,34,86,99]
[1,25,36,88,36,78,144,36,88,101]

Quando mais de um gerador utilizado, devemos levar em conta que para


cada elemento do gerador mais a esquerda sero gerados todos os elementos
dos geradores subseqentes. Vejamos o exemplo a seguir onde se descreve uma
lista de pontos do plano cartesiano, localizados no primeiro quadrante e delimitado
pelas ordenadas 3 e 5.
--- Determinar a lista dos pontos do plano dentro da
-- regiao definida pela origem, a cordenada (eixo y)
-- 5 e a abscissa (eixo x) 3.
-pontos = [ (x,y) | x <- [0..3], y <- [0..5]]
...
Main> pontos
[(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),
(1,0),(1,1),(1,2),(1,3),(1,4),(1,5),
(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),
(3,0),(3,1),(3,2),(3,3),(3,4),(3,5)]

Entre dois geradores podemos usar predicativos, como se observa no


exemplo a seguir.

9
4
--- Determinar a lista dos pontos do plano dentro da
-- regiao definida pela origem, a cordenada (eixo y)
-- 5 e a abscissa (eixo x) 3. Considere apenas os
-- pontos onde x impar e y par.
-pontos1 = [ (x,y) | x <- [0..3], odd x, y <- [0..5], even y ]
...
Main> pontos1
[(1,0),(1,2),(1,4),(3,0),(3,2),(3,4)]

12.6. DEFINIO POR COMPREENSO - EXPLORANDO DETALHES: Vamos


explorar um problema onde exista mais riqueza de detalhes quanto ao uso de
predicativos.
Determinar os pares de valores, onde:

-------

o primeiro mltiplo do segundo;


o primeiro dado pelos elementos impares de uma P.A de primeiro
termo igual a 1, a razo igual 3 e o ultimo termo menor ou igual a
100;
o segundo termo dado pelos elementos de uma P.A de primeiro
termo igual a 1, a razo igual 4 e o ultimo termo menor ou igual a 50;
um dos dois diferente da unidade;
os dois termos so diferentes.

A funo paresE, traduz literalmente o enunciado.


As P.A.'s so realizadas diretamente pelo mecanismo
para definio de P.A. embutido na linguagem.
Os predicativos foram inseridos na posio em que
suas variveis j esto instanciadas.

-paresE1

= [ (x,y) | x <- [1,4..100],


odd x,
y <- [1,5..50],
(x/=1 || y/= 1),
x/=y,
mod x y == 0]

...
Main> paresE1
[(7,1),(13,1),(19,1),(25,1),(25,5),(31,1),(37,1),
(43,1),(49,1),(55,1),(55,5),(61,1),(67,1),(73,1),
(79,1),(85,1), (85,5),(85,17),(91,1),(91,13),(97,1)]

Vejamos algumas observaes sobre a soluo acima apresentada:

5
o predicado odd poderia ser colocado em qualquer lugar mais a frente,
entretanto o desempenho cairia, visto que iramos produzir valores
desnecessrios para "y";
a expresso (x/=1 || y/= 1) desnecessria visto que s ser falsa quando
ambos, x e y, forem iguais a 1, mas nesse caso eles sero iguais e portanto
falsificariam a expresso a seguir x/=y;
podemos reescrever a expresso x <- [1,4..100] de tal maneira que gere
apenas valores impares e assim descartar a expresso odd x. Para tanto
basta mudar a P.A. para [1,7..100];
pode-se observar que os valores de y que interessam so sempre menores
que os de x ( j que y divisor de x). Portanto, a segunda P.A poderia ser
substituda por [1,5..(x-1)]. Acontece que agora poderemos geram valores
para y maiores que 50 e isto no interessa. O que fazer? Que tal substitula por:
[1, 5..(if x < 50 then (x-1) else 50)]

Eis ento uma nova verso para nossa funo:


paresE2

= [ (x,y) | x <- [1,7..100],


y <- [1,5..(if x < 50
then (x-1)
else 50)],
x/=y,
mod x y == 0]

Podemos agora refletir sobre uma possvel generalizao para a nossa


funo, considerando-se duas listas quaisquer. Neste caso, o esforo realizado
para melhorar o desempenho seria em vo porque no conhecemos a priori a
natureza das duas listas. Nossa funo poderia ser:
paresE3 xs ys = [ (x,y) | x <- xs,
odd x,
y <- ys,
x/=y,
mod x y == 0]

Apenas a expresso (x/=1 || y/= 1) poderia ser eliminada. O objetivo de


nossa verso original poderia ser obtido pelo uso da nova funo aplicada s listas
especficas. Conforme se observa a seguir:
Main> paresE3 [1,4..100] [1,5..50]
[(7,1),(13,1),(19,1),(25,1),(25,5),(31,1),(37,1),(43,1),
(49,1),(55,1),(55,5),(61,1),(67,1),(73,1),(79,1),(85,1),
(85,5),(85,17),(91,1),(91,13),(97,1)]
(16878 reductions, 23992 cells)

9
6
Agora podemos ainda inspecionar o que de fato acontece com o
desempenho das trs verses.
Main> paresE1
[(7,1),(13,1),(19,1),(25,1),(25,5),(31,1),(37,1),(43,1),
(49,1),(55,1),(55,5),(61,1),(67,1),(73,1),(79,1),(85,1),
(85,5),(85,17),(91,1),(91,13),(97,1)]
(22894 reductions, 32210 cells)
Main> paresE2
[(7,1),(13,1),(19,1),(25,1),(25,5),(31,1),(37,1),(43,1),
(49,1),(55,1),(55,5),(61,1),(67,1),(73,1),(79,1),(85,1),
(85,5),(85,17),(91,1),(91,13),(97,1)]
(15124 reductions, 22014 cells)

Coloquemos os valores obtidos em uma tabela.


verso
paresE1
paresE2
paresE3

redues clulas
22894 32210
15124 22014
16878 23992

Aqui podemos constatar que a verso paresE3, bastante similar a paresE1, a


menos da generalizao, possui eficincia bem superior. Lembre-se que a nica
diferena a eliminao da comparao dos dois termos com o valor 1.
Para ver o que est acontecendo, vamos construir ainda uma outra verso,
similar a paresE1, eliminando a comparao citada e descrevendo as P.A.'s fora
dos geradores, assimilando-se assim verso paresE3. Veja que com isso a nova
verso, que obtivemos partindo de paresE1, possui eficincia similar a paresE3.
Confirma-se ento a observao de que a definio de listas dentro dos geradores
produz perdas.
paresE4

= [ (x,y) | x <- xs,


odd x,
y <- ys,
x/=y,
mod x y == 0]
where
xs = [1,4..100]
ys = [1,5..50]

...
main> paresE4
[(7,1),(13,1),(19,1),(25,1),(25,5),(31,1),(37,1),(43,1),
(49,1),(55,1),(55,5),(61,1),(67,1),(73,1),(79,1),(85,1),
(85,5),(85,17),(91,1),(91,13),(97,1)]
(16878 reductions, 23992 cells)

9
7

12.7. OPERAES PARA DETERMINAR SUBLISTAS: Existem algumas


operaes predefinidas no HUGS para descrevermos sublistas de uma lista dada.
Nada que no possa ser feito com o que j apresentamos at aqui. Entretanto o
seu uso pode ajudar na prtica do reuso e contribuir bastante para a clareza de
um programa.
Grupo I - Considerando um tamanho especificado
take k xs - define uma lista com os k primeiros elementos de uma lista xs.
drop k xs - define uma lista com os elementos de xs, a partir do elemento
seguinte aos k primeiros.
Vejamos a ilustrao a seguir.
Prelude> take 3 [0..10]
[0,1,2]
(156 reductions, 221 cells)
Prelude> drop 3 [0..10]
[3,4,5,6,7,8,9,10]
(358 reductions, 513 cells)
Prelude> [xs!!i | i <-[0..(k - 1)]]
where xs = [0..10]; k = 3
[0,1,2]
(249 reductions, 336 cells)
Prelude> [xs!!i | i <-[k..length xs - 1]]
where xs = [0..10]; k = 3
[3,4,5,6,7,8,9,10]
(1591 reductions, 2072 cells)
Prelude> (take 3 [1..10] ++ drop 3 [1..10]) == [1..10]
True
(658 reductions, 980 cells)

Na verdade podemos escrever uma descrio geral para take e drop usando
listas por compreenso. Alm disso, sabemos que a concatenao de take e drop
para um certo k, aplicado uma lista xs, igual prpria lista.

take k xs = [xs!!i | i <-[0..(k - 1)]]


drop k xs = [xs!!i | i <-[k..length xs - 1]]
vale o seguinte teorema:
Take k xs ++ drop k xs = xs

Grupo II - Considerando a satisfao de um predicado pred. Vale lembrar que


um predicado uma funo cujo valor resultante do tipo boolean.

9
8
takeWhile pred xs - define uma lista com os primeiros elementos de uma lista xs
satisfazendo o predicado pred.
dropWhile pred xs - define uma lista com os elementos de xs, a partir do primeiro
elemento que no satisfaz o predicado pred.
Vejamos a ilustrao a seguir.
Prelude> takeWhile even [1..10]
[]
Prelude> takeWhile odd [1..10]
[1]
Prelude> dropWhile odd [1..10]
[2,3,4,5,6,7,8,9,10]
Prelude> dropWhile even [1..10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> takeWhile (<5) [1..10]
[1,2,3,4]
Prelude> dropWhile (<5) [1..10]
[5,6,7,8,9,10]
Prelude> takeWhile (<5) [1..10] ++
dropWhile (<5) [1..10] == [1..10]
True

Exerccios:
Kjoj
Ionopi
Oijoip
Joij
Oioi
Iojo

9
9
13. Resolvendo Problemas com Listas
Neste captulos desenvolveremos a soluo para alguns problemas mais
complexos. A inteno apresentar o uso de estratgias de propsito geral que
podem ser teis na resoluo de novos problemas. Discutimos tambm algumas
questes relativas ao desempenho das solues.
13.1

PROBLEMA 1 : Dada uma lista, determine o seu maior elemento.


Comecemos por definir, usando a linguagem de conjuntos, quem este
elemento.
Dizemos que k o maior elemento de um conjunto C, se e somente se, o
subconjunto de C formado por todos os elementos maiores que k vazio.
Em linguagem de lista isto equivale a dizer que se C uma lista, a sublista
de C formada pelos caras de C maiores que k vazia.
Vejamos como fica a codificao em Haskell.
--- definindo uma funo para determinar, em uma lista,
-- a sublista dos elementos maiores que um dado x
-maiores x xs = [ y | y <- xs, y > x]
---- Em listas, podemos ter elementos repetidos, e em particular
-- podemos ter vrios exemplares do maior elemento.
-- Chamemos esses caras de os "maiorais da lista".
-- Vamos construir uma funo para descrev-los.
-maiorais xs = [ k | k <- xs, maiores k xs == [] ]
--- Como eles so todos idnticos podemos tomar o primeiro deles
-- como soluo de nosso problema.
-maximo xs = head (maiorais xs)
--

13.2 PROBLEMA 2: Dada uma lista, verifique se ela no decrescente.


Como aquecimento, vamos considerar listas de nmeros e a noo usual de
ordem no decrescente. Nosso problema :
Antes de programar, vamos resgatar a definio de seqncias no
decrescentes.
Definio : Uma seqncia S est em ordem no decrescente se e somente
se qualquer um de seus elementos menor ou igual aos seus sucessores. Em

1
00
outras palavras, podemos dizer que a coleo de elementos de S que so maiores
que seus sucessores vazia.
--- lista dos maiores que os sucessores
-lms1 xs = [ xs!!i | i <-[0..length xs j <-[i+1..length xs
xs!!i > xs!!j]
--- a seqncia est ordenada se a lista
-- que so maiores que algum sucessor
-ord1 xs = (lms1 xs) == []
...

2],
- 1],
dos elementos
vazia

Main> ord1 [1..10]


True
(10801 reductions, 13891 cells)
Main> ord1 [10,9..1]
False
(405 reductions, 571 cells)

13.3. DISCUTINDO EFICINCIA: Observando a avaliao da funo ord1,


apresentada na seo anterior, para uma lista j ordenada, a lista
[1,2,3,4,5,6,7,8,9,10], constatamos um nmero muito grande de redues.
Convm questionar os motivos.
Main> ord1 [1..10]
True
(10801 reductions, 13891 cells)
Main> ord1 [10,9..1]
False
(405 reductions, 571 cells)

Em geral os motivos para um baixo desempenho so de duas naturezas:


explorao inadequada das propriedades do problema e escolha inadequada dos
mecanismos da linguagem. A seguir fazemos uma pequena explorao desses
dois aspectos.
13.3.1. EXPLORANDO PROPRIEDADES DO PROBLEMA - Analisando a nossa
definio anterior constatamos que ela diz mais do que precisamos. Ela avalia
cada elemento com respeito a todos sucessores. Na verdade, nossa definio
pode ser melhorada. Basta saber que cada elemento tem que ser menor ou igual
ao seu sucessor imediato. Vamos reescrever a nossa definio:
Definio : Uma seqncia S est em ordem no decrescente se e somente
se qualquer um de seus elementos menor ou igual ao seu sucessor imediato.
Em outras palavras, podemos dizer que a coleo de elementos de S que so
maiores que seus sucessores imediatos vazia.

1
01
Vejamos ento a implementao em Haskell e sua aplicao s mesmas
instncias do problema:
--- lista dos elementos maiores que o sucessor imediato
-lms2 xs = [ xs!!i | i <-[0..length xs - 2],
xs!!i > xs!!(i+1)]
-ord2 xs = (lms2 xs) == []
...
Main> ord2 [1..10]
True
(2236 reductions, 2885 cells)
Main> ord2 [10,9..1]
False
(314 reductions, 449 cells)

Podemos observar uma queda no nmero de redues da ordem de 79%!!!


Para o pior caso, ou seja, quando todos os elementos satisfazem a propriedade
estabelecida. No melhor caso, onde o primeiro j no satisfaz a propriedade, a
queda foi da ordem de 22%. Na utilizao de clulas, os ganhos foram da mesma
ordem.
13.3.2. EXPLORANDO OS MECANISMOS DA LINGUAGEM - Uma outra
investida que podemos fazer com respeito ao uso adequado dos mecanismos da
linguagem. As solues acima apresentadas processam as listas atravs de
ndices, ou seja, fazem um acesso aleatrio aos elementos da lista. Como j foi
discutido, o acesso seqencial possui realizao mais eficiente.
--- Para manusear os pares de adjacentes, ao
-- invs de usar ndices, usemos a funo zip
-- aplicada a um par de listas construdas com base em xs
-- a)lista formada pelos elementos de xs, exceto o ltimo,
-que pode ser obtida com a funo init;
-- b)lista formada pelos elementos de xs, exceto o primeiro,
-que pode ser obtida com a funo tail.
-- Com isso obtemos uma lista formada pelos pares adjacentes.
-adjacentes xs = zip (init xs) (tail xs)
...
Main> adjacentes [1..10]
[(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
(414 reductions, 822 cells)
Main> adjacentes [10,9..1]
[(10,9),(9,8),(8,7),(7,6),(6,5),(5,4),(4,3),(3,2),(2,1)]
(364 reductions, 667 cells)
---

1
02
-- A nova funo para definir lista dos maiores
-- que os sucessores. Agora trabalharemos com os pares
-lms3 ps = [ (x,y) | (x,y) <- ps, x>y]
--- A nova verso de 'ord'
-ord3 xs = lms3 (adjacentes xs) == []
...
Main> ord3 [1..10]
True
(313 reductions, 483 cells)
Main> ord3 [10,9..1]
False
(82 reductions, 145 cells)

O ganho obtido para a instncia considerada foi de 86% no nmero de


redues e de 83% no nmero de clulas utilizadas, com respeito segunda
definio.
Exerccios
1. Lknkhn
2. Lknlk
3. Lkhlk
4. lhnlkhlkj~joiwehj
5. Oihophp

1
03
14. Paradigma Aplicativo

14.1. INTRODUO: A descrio de funes, como acontece com outras formas


de representao de conhecimento, admite vrios estilos. Dependendo do
problema que estamos tratando, um estilo pode ser mais conveniente que outros.
Podemos dizer que influi muito na escolha, o quanto desejamos ou necessitamos,
falar sobre como computar uma soluo. A descrio de solues tem um
espectro de operacionalidade que vai do declarativo at o procedural, em outras
palavras, do que desejamos computar ao como queremos computar..
Uma situao que ocorre com freqncia na descrio de funes a
necessidade de aplicar uma funo, de forma cumulativa, uma coleo de
elementos. Em outras palavras, desejamos generalizar uma operao para que
seu uso se estenda a todos os elementos de uma lista. Chamemos este estilo de
paradigma aplicativo.
Por exemplo, suponha que desejamos obter a soma de todos os elementos
de uma lista. A operao adio (+) segundo sabemos, de natureza binria, ou
seja, opera sobre dois elementos produzindo um terceiro. Para operar sobre todos
os elementos de uma lista de forma a obter a soma total, podemos oper-los dois
a dois, obtendo com isso resultados intermedirios, que por sua vez podero ser
novamente operados e assim sucessivamente at que se obtenha o resultado
final. Observemos o processo para uma instncia:
Obter a soma dos elementos da lista [5, 9, 3, 8, 15, 16]
Podemos tomar os pares de elementos, primeiro com segundo, terceiro
com quarto e assim sucessivamente.
expresso

+ [5, 9, 3, 8, 15, 16]


+ [14, 3, 8, 15, 16]
+ [14, 11, 15, 16]
+ [14, 11, 31]
+ [25, 31]
+ [56]

nova expresso

+ [14, 3, 8, 15, 16]


+ [14, 11, 15, 16]
+ [14, 11, 31]
+ [25, 31]
+ [56]

reduo
5 + 9 = 14
3 + 8 = 11
15 + 16 = 31
14 + 11 = 25
25 + 31 = 56

56

A escolha dos pares, no caso da adio, no importa. As redues poderiam


ser aplicadas em qualquer ordem, visto que a operao adio comutativa. Se,
pode ser qualquer uma, ento podemos estabelecer uma ordem, como por

1
04
exemplo, da esquerda para a direita, usando em cada nova reduo o elemento
resultante da reduo anterior.

Expresso

+ [5, 9, 3, 8, 15, 16]


+ [14, 3, 8, 15, 16]
+ [17, 8, 15, 16]
+ [25, 15, 16]
+ [40, 16]
+ [56]

nova expresso

+ [14, 3, 8, 15, 16]


+ [17, 8, 15, 16]
+ [25, 15, 16]
+ [40, 16]
+ [56]

Reduo
5 + 9 = 14
14 + 3 = 17
17 + 8 = 25
25 + 15 = 40
40 + 16 = 56

56

Em HUGS existe um operador que permite a descrio de computaes


desta natureza. Este operador denomina-se foldl. A sua utilizao requer ainda
que seja indicado um valor especial para a operao considerada. Este elemento
tomado como ponto de partida para as redues, ou seja, a primeira aplicao
da operao sobre o valor especial e o primeiro elemento da lista.
Eis a sintaxe:

foldl <operao> <valor especial> <lista>


A ordem estabelecida para as redues semelhante ilustrao acima, ou
seja, caminha-se da esquerda para direita, usando o resultado da reduo anterior
para a nova reduo.
expresso

nova expresso

foldl op ve [x0, x1, x2,...,xn]


op [(op (op ve x0) x1), x2,...,xn]

op [(op ve x0), x1, x2,...,xn]


op [op((op (op ve x0) x1) x2),...,xn]

op [op(op((op (op ve x0) x1) x2)... xn)]

op(op((op (op ve x0) x1) x2)... xn)

Merece aqui um destaque, foldl na verdade um funo, com 3 parametros,


sendo que um deles uma outra funo. Dizemos neste caso que foldl uma
funo de segunda ordem.
O tipo da operao tem que ser:

1
05
<alfa> -> <beta> -> <beta>
onde :
<alfa> pode ser do mesmo tipo de <beta>;
<beta> tem que ser do tipo dos componentes
da lista;
o valor especial do tipo <alfa>

Vejamos ento a definio do operador sum disponvel no HUGS e cujo


objetivo a descrio da soma dos elementos de uma lista.

sum xs = foldl (+) 0 xs

OBS:
1. Os operadores infixados so indicados entre parntesis.
2. O valor especial o zero, visto que no desejamos que o valor
especial modifique o resultado da soma de todos os elementos.
Entretanto, ele joga um papel muito especial quando a lista for vazia.
prelude> sum []
0

3. Em exemplos futuros veremos outros usos para o valor especial.

14.2. ALGUMAS OPERAES IMPORTANTES: Assim como a somatria,


existem outras operaes importantes, de grande utilidade, que podem ser obtidas
pelas seguintes equaes usando foldl.
--- produto
-valor especial = 1
-product xs = foldl (*) 1 xs
--- conjuno
-valor especial = True
-and xs = foldl (&&) True xs
--- disjuno
-valor especial = False
-or xs
= foldl (||) False xs

Exemplo 01: Usando product para descrever o fatorial de um nmero

1
Sabemos que: O fatorial de um nmero
ao produto de todos os nmeros naturais de 1 at n.

natural

n>0

06
igual

--- definio de fatorial


-fat n = product [1..n]
...
? fat 5
120
? fat 0
1
? fat 1
1

Exemplo 02: Podemos usar a disjuno (or) generalizada para definir uma
funo que avalia se em uma dada lista de nmeros pelo menos um deles
impar.
--- pelo menos um impar
-umImpar xs = or [odd x | x <- xs]
...
? umImpar [2,2,2,2,2,2,2,2]
False
? umImpar [2,2,2,1,2,2,2,2]
True
? umImpar []
False

14.3. O MENOR ELEMENTO DE UMA LISTA: Estamos interessados em obter


uma funo que associe uma lista xs com o elemento de xs que seja o menor de
todos.
Anteriormente j apresentamos uma verso para a funo que descreve o
maior elemento de uma lista, que bastante similar a esta. Na oportunidade
exploramos uma propriedade que o elemento maior de todos deve satisfazer. No
caso do menor elemento, podemos explorar uma propriedade anloga.
Em uma lista xs, dizemos que k o menor elemento de xs, se e somente se
a sublista de xs formada por elementos menores que k vazia.

1
07
--- menores descreve os elementos menores que um
-- dado x em uma lista xs
-menores x xs = [ y | y <- xs, y < x]
-- minimo descreve a sublista de xs dos elementos
-- que no possuem menores que eles em xs
-minimos xs = [ k | k <- xs, menores k xs == [] ]
--- Como eles so todos idnticos podemos tomar o
-- primeiro deles
-- como soluo de nosso problema.
-menorL0 xs = head (menores xs)

Vamos explorar agora o problema a partir da generalizao da operao


menor. Em sua forma bsica, a funo menor associa dois nmeros quaisquer
com o menor entre eles. Precisamos identificar um elemento que no interfira no
resultado para fazer o papel de valor especial. Para a operao menor podemos
observar que este papel pode ser desempenhado por qualquer um dos elementos
da lista, visto que o menor entre dois valores idnticos o prprio valor. Como
pode ser qualquer um, podemos escolher o primeiro elemento de xs (head).
--- menor de dois
-menor x y = if x < y then x else y
--- menor da lista
-menorL xs = foldl menor (head xs)xs
...
? menorL [5,5,4,4,4,6,6,6,3,3,3,11,1,0]
0
(84 reductions, 157 cells)
? menorL [5]
5
(5 reductions, 13 cells)
? menorL [ ]
ERROR: Unresolved overloading
*** type
: Ord a => a
*** translation : menorL []

Podemos observar aqui que a funo menorL parcial pois no se aplica a


lista vazia.
14.4. INSERO ORDENADA E ORDENAO DE UMA LISTA: A ordenao de
dados uma das operaes mais realizadas em computao. Diariamente, em
todos os computadores do mundo, faz-se uso intensivo dela. Este assunto muito
especial e por isso mesmo profundamente estudado. Cabe-nos aqui fazer uma

1
08
breve passagem pelo assunto, sem, contudo nos aprofundarmos nas questes de
eficincia, que central no seu estudo.
Ser que podemos usar o conceito de generalizao de uma operao para
descrever a ordenao de uma lista? Que operao seria essa?
14.4.1. INSERO EM LISTA ORDENADA - Vamos comear discutindo
uma outra questo mais simples: dada uma lista, com seus elementos j dispostos
em ordem no decrescente, como descrever uma lista na mesma ordem,
acrescida de um elemento tambm fornecido?
Podemos observar que se a lista xs est em ordem no decrescente, com
respeito ao elemento x (dado), podemos descrev-la atravs de dois segmentos:
xs = <menores que x> ++ <maiores ou iguais a x>
Para acrescentar x a xs, basta concatenar x entre os dois segmentos,
obtendo a nova lista ys, assim:
ys = <menores que x em xs> ++ [x] ++ <maiores ou iguais a x em xs>
--- insero ordenada
--insord xs x = takeWhile (< x) xs
++ [x]
++ dropWhile (< x) xs
...
Main> insord [] 10
[10]
(27 reductions, 49 cells)
Main> insord [10] 20
[10,20]
(54 reductions, 84 cells)
Main> insord [10,20] 30
[10,20,30]
(79 reductions, 119 cells)
Main> insord [10,20,30] 5
[5,10,20,30]
(71 reductions, 110 cells)
Main> insord [5,10,20,30] 25
[5,10,20,25,30]
(126 reductions, 183 cells)

14.4.2. Ordenao - A aplicao sucessiva de insord, conforme ilustrada


acima, nos d uma pista para nossa generalizao. Podemos pegar cada
elemento da lista a ser ordenada e inseri-lo em ordem em uma outra lista que ser

1
09
paulatinamente construda, j ordenada. Vamos seguir o exemplo acima, onde
desejamos ordenar a lista [10,20,30,5,25]:

lista parcial
[]
[10]
[10,20]
[10,20,30]
[5, 10, 20, 30]

novo
elemento
10
20
30
5
25

reduo
[10]
[10,20]
[10,20,30]
[5, 10, 20, 30]
[5, 10, 20, 25, 30]

O ponto de partida, neste caso, a lista vazia. Vamos tomar ento a lista
vazia como o valor especial. Vejamos como fica ento nossa definio para
ordenao de listas.
--- ordenao
-ordena xs = foldl insord [] xs
...
Main> ordena [10,20,30,5,25]
[5,10,20,25,30]
(220 reductions, 344 cells)
Main> ordena [1..10]
[1,2,3,4,5,6,7,8,9,10]
(1055 reductions, 1505 cells)
Main> ordena [10,9..1]
[1,2,3,4,5,6,7,8,9,10]
(448 reductions, 712 cells)

14.5. INVERSO DE UMA LISTA: Dada uma lista xs, desejamos descrever a lista
formada pelos elementos de xs tomados em ordem inversa.
Para resolver o problema precisamos inventar uma funo bsica passvel de
generalizao.
Vamos comear descrevendo a funo insAntes.

1
10
--- Insere um elemento antes do primeiro elemento
-- de uma dada lista. Funo similar ao operador
-- (:) exceto pela ordem invertida dos parmetros
-insAntes xs x = x : xs
...
Main> insAntes [1..5] 0
[0,1,2,3,4,5]
(171 reductions, 255 cells)
Main> insAntes [] 0
[0]
(22 reductions, 29 cells)

Tentemos agora a generalizao. A inteno incluir cada elemento da lista


xs que desejamos inverter, antes do primeiro elemento de uma lista que iremos
construindo gradativamente. O valor especial ser a lista vazia. Vejamos um
exemplo onde inverteremos a lista [0, 1, 2, 3, 4]
lista parcial
[]
[0]
1, 0]
[2, 1, 0]
[3, 2, 1, 0]

novo
elemento
0
1
2
3
4

reduo
[0]
[1, 0]
[2, 1, 0]
[3, 2, 1, 0]
[4, 3, 2, 1, 0]

Vamos ento usar o operador foldl para construir a generalizao desejada:


-- inversao
-inverte xs = foldl insAntes [] xs
...
Main> inverte [0..4]
[4,3,2,1,0]
(172 reductions, 259 cells)
Main> inverte [4,3..4]
[4]
(74 reductions, 110 cells)
...
Main> reverse [4,3..4]
[4]
(74 reductions, 111 cells)
Main> reverse [0..4]
[4,3,2,1,0]
(171 reductions, 257 cells)

1
11
Observe a similaridade entre o desempenho da funo reverse, pr-definida,
com o desempenho da inverte que acabamos de definir.

14.6. INTERCALAO DE LISTAS: Dadas duas lista xs e ys, ambas em


ordem no decrescente, desejamos descrever uma nova lista em ordem no
decrescente, formada por todos os elementos das duas listas.
Um processo bastante conhecido, chamado de balance line, consiste em ir
transferindo para a nova lista, os elementos de uma das listas de entrada,
enquanto estes forem menores que os da outra. Quando a condio no mais
satisfeita, fazemos o mesmo para a outra lista.
Por exemplo, vamos intercalar as listas [2, 4, 6, 8] e [1, 3, 5]. Vejamos o
desenrolar do processo.
lista parcial
[]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 8]

Andamento
em xs
[2, 4, 6, 8]
[2, 4, 6, 8]
[ 4, 6, 8]
[ 4, 6, 8]
[6, 8]
[6, 8]
[ 8]
[]

Andamento
em ys
[1, 3, 5]
[3, 5]
[3, 5]
[5]
[5]
[]
[]
[]

Reduo
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 8]

Vamos precisar aqui de uma bela engenharia para a construo da funo a


generalizar. Desta vez, nossa entrada formada por duas listas e como sabemos
o operador foldl, a cada vez, processa um elemento de uma determinada lista.
Isto nos leva a ter que inventar tambm a lista a ser processada.
A funo bsica pode ser inventada a partir da descrio de um passo do
processo que denominamos de balance line. Em cada passo temos como entrada
uma lista parcialmente construda e duas listas parcialmente processadas. Como
sada teremos mais um passo de construo da lista resultante e o andamento no
processamento de uma das listas. Na lista em construo devemos inserir o
menor entre os cabeas (head) das duas listas. Aquela que tiver o menor cabea
dar origem a uma nova lista, da qual foi excludo o primeiro elemento, ou seja,
ser idntica ao resto (tail) da lista escolhida.

1
12
--- Descrio de um passo do Balance Line.
-- 1) Quando uma das duas listas for vazia a
-outras diretamente concatenada no final
-da lista em construo.
-passoBL (xs,ys,zs) = if (ys == [])
then ([],[],zs++xs)
else if (xs == [])
then ([],[],zs++ys)
else if (head xs <= head ys)
then (tail xs,ys,zs++[head xs])
else (xs, tail ys,zs++[head ys])
...
... aplicao sucessiva da funo passoBL intercalao
... das listas acima propostas
...
Main> passoBL ([2,4,6,8],[1,3,5],[])
([2,4,6,8],[3,5],[1])
(121 reductions, 219 cells)
Main> passoBL ([2,4,6,8],[3,5],[1])
([4,6,8],[3,5],[1,2])
(122 reductions, 222 cells)
Main> passoBL ([4,6,8],[3,5],[1,2])
([4,6,8],[5],[1,2,3])
(123 reductions, 225 cells)
Main> passoBL ([4,6,8],[5],[1,2,3])
([6,8],[5],[1,2,3,4])
(124 reductions, 228 cells)
Main> passoBL ([6,8],[5],[1,2,3,4])
([6,8],[],[1,2,3,4,5])
(128 reductions, 239 cells)
Main> passoBL ([6,8],[],[1,2,3,4,5])
([],[],[1,2,3,4,5,6,8])
(116 reductions, 223 cells)
...
Main> passoBL ([1..5],[],[])
([],[],[1,2,3,4,5])
(190 reductions, 329 cells)
Main> passoBL ([],[1..5],[])
([],[],[1,2,3,4,5])
(193 reductions, 339 cells)
Main> passoBL ([1..3],[4..5],[])
([2,3],[4,5],[1])
(219 reductions, 371 cells)

A generalizao, de forma que possamos aplicar a funo gradativamente,


de tal forma que todo o processo se complete, requer a inveno de uma lista
sobre a qual ocorra a repetio. O nmero de aplicaes sucessivas ser no
mximo igual soma dos comprimentos das listas a serem intercaladas. Podemos
ento definir a aplicao sobre a lista dos nmeros de 1 at a soma dos
tamanhos.

1
13
--- Funo para Intercalar duas listas ordenadas
-- 1) a funo passoBL repetidamente aplicada, sobre
-o resultado obtido no passo anterior;
-- 2) a funo passoBL binria, como exigido por foldl;
-- 3) a aplicao sucessiva controlada pelo comprimento
-da lista resultante;
-- 4) o resultado final obtido pela seleo do terceiro
-elemento da tripla atravs da primitiva "thd3"
-baLine xs ys = thrd3 (baLine3 xs ys)
-thrd3 (x,y,z) = z
-baLine3 xs ys = foldl passoBL (xs,ys,[]) [1..tr]
where
tr = (length xs)+(length ys)
--- Descrio de um passo do Balance Line.
-- 1) Quando uma das duas listas for vazia a
-outras diretamente concatenada no final
-da lista em construo.
-- 2) O parmetro k apenas para estabelecer o tipo
-binrio exigido por foldl
-passoBL (xs,ys,zs) k = if (ys == [])
then ([],[],zs++xs)
else if (xs == [])
then ([],[],zs++ys)
else if (head xs <= head ys)
then (tail xs,ys,zs++[head xs])
else (xs, tail ys,zs++[head ys])
...
Main> thrd3 (10,20,30)
30
(11 reductions, 12 cells)
Main> baLine3 [1..3] [4..6]
([],[],[1,2,3,4,5,6])
(514 reductions, 896 cells)
Main> baLine [1..3] [4..6]
[1,2,3,4,5,6]
(485 reductions, 784 cells)
Main> baLine [1..5] [3..7]
[1,2,3,3,4,4,5,5,6,7]
(807 reductions, 1326 cells)
Main> baLine [2, 4, 6, 8] [1, 3, 5]
[1,2,3,4,5,6,8]
(425 reductions, 696 cells)

Exerccios:
1. Sdknfvlnlc
2. Fsponmposfdnponsdf
3. psnmfdponmposds

1
14
15. Processamento de Cadeias de Caracteres primeiros passos

15.1. INTRODUO: Alm de nmeros, nosso mundo povoado por textos.


Cada vez mais se torna presente o uso de computadores para nos auxiliar na
tarefa de armazenar, recuperar e processar documentos. Neste captulo estamos
interessados em fazer uma breve introduo ao uso de computadores nessas
tarefas.
O ponto de partida o tipo caracter (chr), que nos permite representar textos
na memria (principal e secundria) dos computadores. Veremos tambm como
agrup-los para compor palavras, frases e por fim documentos.

15.2. O TIPO CHAR: O tipo char formado por um conjunto de smbolos. Um


outro nome usado para esta coleo alfabeto, ou seja, o conjunto de tomos que
serviro de base para a construo de cadeias complexas, inclusive os textos
usuais. Entre os smbolos citados podemos destacar trs agrupamentos
relevantes, tais como:
1. As letras maisculas do alfabeto;
2. As letras minsculas do alfabeto;
3. Os algarismos arbicos;
Estes trs agrupamentos gozam de uma propriedade muito importante.
Dentro deles os smbolos possuem uma relao de ordem, de tal forma que
podemos usar a noo usual de ordenao para letras e algarismos.
Alm destes, podemos citar ainda os sinais de pontuao e alguns smbolos
com funes especiais, como, por exemplo, indicador de final de linha de texto. Os
smbolos so sempre apresentados em HUGS entre aspas simples, para que
possam ser diferenciados dos nomes de parmetros, funes e outros. Por
exemplo, a letra a deve ser denotada por 'a' .
A definio a seguir ajuda a esclarecer esta necessidade.
f a = (a, 'a')
Aqui usamos a letra a trs vezes. A primeira, da esquerda para direita,
nomeia um parmetro da funo f. Na segunda ocorrncia, utilizamos o
parametro da funo para se constituir do primeiro elemento de uma tupla. J a
terceira ocorrncia se refere constante a.
Vejamos as respostas do sistema para diferentes usos da funo f
1 Main> f 3
(3,'a')

1
15
2 Main> f 5
(5,'a')
3 Main> f a
ERROR - Undefined variable "a"
4 Main> f 'a'
('a','a')
5 Main> f 'aa'
ERROR - Improperly terminated character constant
6 Main> f 'b'
('b','a')
7 Main> f a where a='a'
('a','a')

Nas situaes 1, 2, e 6, o parametro a instanciado para os valores 3, 5 e b ,


resultando nos pares (3, a), (5,a) e (b, a). Na situao 4, o parmetro a
instanciado para a constante a, produzindo o par (a, a). Na situao 3, o uso de
a est incorreto, pois como no est entre as aspas simples, interpretado como
um parmetro, que no est instanciado quando deveria estar. Na situao 7, ao
contrrio da situao 3, o valor de a instanciado atravs da clusula where e a
situao fica similar situao 4.
A coleo total dos smbolos de nosso alfabeto forma uma seqncia de tal
forma que podemos fazer o mapeamento entre a subseqncia de nmeros
naturais, de zero (0) a 255 e a seqncia de smbolos.
Duas funes bsicas permitem que se faa a converso entre as duas
seqncias:
1. A funo chr associa um nmero natural no intervalo [0,255] com o caracter
correspondente. Por exemplo, chr 64 = '@' e chr 38 = '&'.
2. A funo ord faz o mapeamento inverso, ou seja, associa um smbolo com
o nmero natural correspondente. Por exemplo, ord '?' = 63 e ord '%' = 37.
A tabela a seguir apresenta alguns dos agrupamentos importantes.
Algarismos

Letras
Maisculas

Letras
Minsculas

1
16
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96

97
98
99
100
101
102
103
102
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

123
124
125
126

Alm das operaes ord e chr, podemos contar com os operadores


relacionais que foram apresentados no Captulo 6. Da mesma forma que existem
os operadores para comparao de nmeros, existem os operadores relacionais
que comparam dois smbolos, como no exemplo:
Prelude> 'c' > 'h'
False

O significado de uma operao relacional sobre characteres determinado


com base na ordem destes com respeito tabela apresentada para codificao
desses smbolos. Assim, podemos dizer que:
Se x e y so do tipo caractere, x > y se e somente se ord x > ord y
Podemos agora construir algumas definies interessantes, conforme se
apresenta nos quadros a seguir.:

1
17
--- verifica se um dado smbolo letra
-letra x = (maiuscula x) || (minuscula x)
-maiuscula
x = pertence x ('A','Z')
minuscula
x = pertence x ('a','z')
pertence x (a,b) = (x >= a) && (x <= b)

--- verifica se um smbolo um algarismo


-algarismo
x = pertence x ('0','9')
--- Associa uma letra minuscula com a sua
-- correspondente maiuscula e mantm o
-- smbolo fornecido nos demais casos
-caps x = if minuscula x
then chr (ord x - 32)
else x

--- Determina a posio relativa de uma letra


-- dentro do alfabeto, onde as maisculas e
-- minsculas possuem a mesma posio.
-- Outros smbolos devem ser associados ao
-- valor 0 (zero)
-ordAlfa x = if letra x
then ord (caps x) - 64
else 0

Eis a aplicao em algumas instncias:

Eis
mais
alguns
exemplos
de funes
com o tipo
char.
--

1
18
-- verifica se um smbolo uma letra vogal
-vogal x
= letra x && ocorre (caps x) vogais
where
vogais = ['A','E','I','O','U']
-ocorre x xs = or [x == y | y<- xs]

--- verifica se um smbolo uma letra


-- consoante
-consoante x = letra x && (not (vogal x))
--

--- Descreve uma lista de pares onde o primeiro termo


-- um nmero entre 0 e 255 e o segundo o caracter
-- correspondente. O intervalo desejado informado
-- por um par de valores no intervalo 0 a 255.
-tabOrdChr (i,f) = [(x, chr x) | x <- [i..f]]

Vejamos alguns exemplos de uso das definies acima apresentadas:


Main> tabOrdChr (65,70)
[(65,'A'),(66,'B'),(67,'C'),(68,'D'),(69,'E'),(70,'F')]
(357 reductions, 604 cells)
Main> tabOrdChr (97,102)
[(97,'a'),(98,'b'),(99,'c'),(100,'d'),(101,'e'),(102,'f')]
(357 reductions, 607 cells)
Main> tabOrdChr (45,50)
[(45,'-'),(46,'.'),(47,'/'),(48,'0'),(49,'1'),(50,'2')]
(357 reductions, 604 cells)

15.3. O TIPO STRING: Podemos agrupar tomos do tipo caracter (char) para
formar o que denominamos de cadeia de caracteres, usualmente chamadas de
"palavra". O mecanismo para agregar o construtor da lista. Podemos por
exemplo, escrever em HUGS a lista ['c','i','d','a','n','i','a'] para representar a palavra
cidadania.
Assim procedendo podemos escrever qualquer texto, uma vez que um texto
no nada mais nada menos que uma longa cadeia de smbolos envolvendo
letras e sinais de pontuao. A separao de palavras obtida pelo uso de um
caracter especial, denominado de espao, que tem representao interna igual a
32. Por exemplo, para representar a expresso "Vamos nessa!", usamos a lista:
['V','a','m','o','s',' ','n','e','s','s','a','!'].

1
19
Uma boa notcia que o HUGS nos proporciona uma maneira mais amistosa
para tratar com lista de caracteres. Em HUGS podemos representar uma lista de
caracteres, envolvendo a cadeia por aspas duplas, o que por certo, alm de mais
elegante e legvel, no poupa trabalho. Por exemplo, a cadeia acima representada
por ser tambm escrita na seguinte forma:
"Vamos nessa!"
uma lista de caracteres o HUGS associa um tipo sinnimo, denominado
string. Assim, as duas representaes acima so idnticas, conforme podemos
observar na avaliao abaixo:
Prelude> "Vamos nessa!" == ['V','a','m','o','s',' ','n','e','s','s','a','!']
True
(64 reductions, 102 cells)

Um bom lembrete que, cadeias de caracteres so definidas como listas, e


como tais, podemos usar sobre elas todas as operaes que sabemos at agora
sobre listas.
Por exemplo, podemos construir uma funo para contar a quantidade de
vogais existente em uma cadeia.
contaVogais xs = length vogais
where
vogais = [x | x <-xs, vogal x]
...
Main> contaVogais "Vamos nessa!"
4
(966 reductions, 1383 cells)

15.4. FUNES BSICAS PARA O TIPO STRING: Uma cadeia de caracteres,


por ser uma lista, herda todas as operaes que j apresentamos para as listas.
Alm dessas, podemos contar ainda com algumas operaes que apresentamos a
seguir:
words xs - Associa uma cadeia de caracteres com a lista de palavras nela
contida. Entende-se por palavra um agrupamento de smbolos diferentes do
smbolo espao (" ").
Prelude> words "Se temos que aprender a fazer, vamos
aprender fazendo!"
["Se","temos","que","aprender","a","fazer,",
"vamos","aprender","fazendo!"]
(2013 reductions, 3038 cells)

1
20
Podemos observar que os smbolos usuais de separao (por exemplo, "," e
"!" so considerados como parte das palavras. Vamos agora construir uma funo
que considere os smbolos usuais de separao, alm do espao.
--- A funo palavras
-palavras xs = [ takeWhile letra x | x <- words xs]
---...
Main> palavras "Se temos que aprender a fazer, vamos aprender fazendo!"
["Se","temos","que","aprender","a","fazer","vamos","aprender","fazendo"]
(3869 reductions, 5444 cells)
Main> palavras "jose123 maria456 joana!!!"
["jose","maria","joana"]
(1445 reductions, 2081 cells)
Main> words "jose123 maria456 joana!!!"
["jose123","maria456","joana!!!"]
(951 reductions, 1423 cells)

De fato, a funo palavras trata a questo a que nos propnhamos,


abandonar os smbolos de pontuao. Acontece que ela abandona muito mais que
isso, como podemos ver no exemplo, onde a cadeia "jose123" perde o seu sufixo
numrico, tornando-se apenas "jose".

Vamos construir uma nova funo ento onde isso possa ser resgatado.
--- A funo palavras1
-palavras1 xs = [ takeWhile alfa x | x <- words xs]
where alfa x = letra x || algarismo x
---...
Main> palavras1 "x123 y456 aux!!!"
["x123","y456","aux"]

Bom, parece que agora temos uma soluo adequada.

1
21

Exerccios
Kjbkj
Kjn
Ono
Onoi

1
22
16. O PARADIGMA RECURSIVO

16.1. INTRODUO: Como j falamos anteriormente, existem vrias maneiras de


definir um conceito. A essas maneiras convencionamos chamar de paradigmas.
Aqui trataremos de mais um destes, o paradigma recursivo. Dizer que trataremos
de mais um simplificar as coisas, na verdade este paradigma um dos mais
ricos e importantes para a descrio de computaes. O domnio deste paradigma
de fundamental importncia para todo aquele que deseja ser um expert em
Programao de Computadores enquanto cincia e tecnologia.
De uma maneira simplificada podemos dizer que o ncleo deste paradigma
consiste em descrever um conceito de forma recursiva. Isto equivale a dizer que
definiremos um conceito usando o prprio conceito. Apesar de disto parecer muito
intrigante, no se assuste, aos poucos, quando esboarmos melhor a idia ela se
mostrar precisa, simples e poderosa.
Vamos pensar num conceito bem corriqueiro. Que tal definirmos o conceito
escada.
Como podemos descrever escada usando a prpria escada? A resposta
bem simples:
Uma escada igual a um degrau seguido de uma escada (Figura 15.1).

escada

escada

degrau
Figura 15.1 Uma escada
Fcil no ? Ser que isto basta? Onde est o truque? Parece que estamos
andando em crculo, no mesmo? Para entender melhor vamos discutir a seguir
alguns elementos necessrios para a utilizao correta da recurso na definio
de novas funes.

16.2. DESCRIO RECURSIVA DE UM CONCEITO FAMILIAR: Antes de


avanar em nossa discusso vamos apresentar mais um exemplo. Desta vez

1
23
usaremos um que bastante familiar para alunos de cincias exatas. Estamos
falando da descrio do fatorial de um nmero. J vimos neste curso uma forma
de descrever este conceito dentro do HUGS quando estudamos o paradigma
aplicativo. Na oportunidade usamos a seguinte descrio:

O fatorial de um nmero natural n > 0 igual


ao produto de todos os nmeros naturais de 1 at n.

Ou ainda em notao mais formal:

n ! = 1 x 2 x 3 x ... x n
Em HUGS, como j vimos, teremos a seguinte definio:
--- definio (aplicativa) de fatorial
-fat n = product [1..n]
...
? fat 5
120
? fat 0
1
? fat 1
1

H uma outra forma de definir, tambm familiar aos alunos do primeiro ano
universitrio:
O Fatorial de um nmero natural n igual ao produto deste nmero pelo fatorial
de seu antecessor.
Novamente, sendo mais formal, podemos escrever:

n ! = n x (n - 1) !
E em HUGS, como ficaria? Que tal a definio a seguir?
--- definio recursiva de fatorial
-fat n = n * fat (n - 1)

Vamos exercitar a definio:

1
24
Main> fat 5
(23967 reductions, 47955 cells)
ERROR: Control stack overflow

Bom, parece que houve um pequeno problema com nossa definio. A


avaliao de fat 5 produziu uma situao de erro. Vamos deixar para entender
este erro melhor para depois. Por enquanto j podemos adiantar que ele foi
provocado por um pequeno esquecimento de nossa parte.
Na verdade a nossa definio recursiva para fatorial estava incompleta. Esta
que exibimos s se aplica aos naturais maiores que zero. A definio do fatorial de
zero no recursiva, ela independente:
O fatorial de zero igual a 1.
Temos ento duas definies para fatorial e precisamos integr-las. Vejamos
uma tentativa:
O Fatorial de um nmero natural n :
1. igual a 1 se n=0;
2. igual ao produto deste nmero pelo fatorial de
seu antecessor, se n > 0
Vamos ver como essa integrao pode ser feita em HUGS. Podemos de
imediato observar que trata-se de uma definio condicional e logo nos vem a
lembrana de que nossa linguagem possui um mecanismo, as expresses
condicionais.
--- definio recursiva de fatorial
-- (corrigida)
-fat n = if n==0
then 1
else n * fat (n - 1)

Vamos submeter algumas situaes para o HUGS:


Main> fat 5
120
(79 reductions, 124 cells)
Main> fat 20
2432902008176640000
(258 reductions, 466 cells)
Main> fat 0
1
(18 reductions, 18 cells)

1
25
Pelo visto agora deu tudo certo.
16.3. ELEMENTOS DE UMA DESCRIO RECURSIVA: Em uma descrio
recursiva devemos ter em conta certo elementos importantes. fundamental que
todos eles sejam contemplados para que nossas descries estejam corretas. O
exemplo anteriormente apresentado suficiente para ilustrar todos eles. Vamos
ento discuti-los:
Definio geral : Toda definio recursiva tem duas partes, uma delas se
aplica a um valor qualquer do domnio do problema, denominamos de geral. Esta
tem uma caracterstica muito importante, o conceito que est sendo definido deve
ser utilizado. Por exemplo, para definir fatorial de n, usamos o fatorial do
antecessor de n. Observe aqui, entretanto que o mesmo conceito foi utilizado, mas
no para o mesmo valor. Aplicamos o conceito a um valor mais simples, neste
caso o antecessor de n.
Definio independente : A outra parte da definio destinada ao
tratamento de um valor to simples que a sua definio possa ser dada de forma
independente. Este elemento tambm conhecido como base da recurso. No
caso do fatorial, o valor considerado o zero.
Obteno de valores mais simples : Para aplicar o conceito a um valor
mais simples precisamos de uma funo que faa este papel. No caso do fatorial,
usamos a subtrao de n por 1, obtendo assim o antecessor de n. Em cada caso,
dependendo do domnio do problema e do problema em si, precisaremos
encontrar a funo apropriada.
Funo auxiliar : Na definio geral, para obter um valor usando o valor
considerado e o valor definido recursivamente, em geral faz-se necessrio o uso
de uma funo auxiliar. Algumas vezes esta funo pode ser originada a partir de
um conceito aplicvel a dois elementos e que desejamos estender aos elementos
de uma lista. Um exemplo o caso da somatria dos elementos de uma lista,
como veremos adiante. No caso do fatorial esta funo a multiplicao.
Garantia de atingir o valor independente : fundamental que a aplicao
sucessiva da funo que obtm valores mais simples garanta a determinao do
valor mais simples. Este valor tambm denominado de base da recurso. Por
exemplo, no caso do fatorial, sabemos que aplicando a subtrao sucessivas
vezes produziremos a seqncia:
n, (n-1), (n-2), ... 0
Esta condio fundamental para garantir que ao
avaliarmos uma expresso atingiremos a base da recurso.
Voltemos definio do fatorial para destacarmos os elementos acima
citados, como podemos observar no quadro esquemtico a seguir:

1
26

16.4. AVALIANDO EXPRESSES: A esta altura dos acontecimentos a


curiosidade sobre como avaliar expresses usando conceitos definidos
recursivamente j deve estar bastante aguada. No vamos, portanto retardar
mais essa discusso. Apresentamos a seguir um modelo bastante simples para
que possamos entender como avaliar expresses que usam conceitos definidos
recursivamente. Novamente no precisaremos entender do funcionamento interno
de um computador nem da maneira como uma determinada implementao de
HUGS foi realizada. Basta-nos o conceito de reduo que j apresentamos
anteriormente.
Relembremos o conceito de reduo. O avaliador deve realizar uma
seqncia de passos substituindo uma expresso por sua definio, at que se
atinja as definies primitivas e os valores possam ser computados diretamente.
Vamos aplicar ento este processo para realizar a avaliao da expresso

fat 5
passo

Reduo

Justificativa

1
27
0 fat 5
1 5 * fat 4
2 5*(4 * fat 3)
3 5*(4* (3 * fat 2))
4 5*(4*(3*(2 * fat 1)))
5 5*(4*(3*(2*(1 * fat 0)
6 5*(4*(3*(2*(1 * 1))))
7 5*(4*(3*(2*1)))
8 5*(4*(3*2)
9 5*(4*6)
10 5 * 24
11 120

expresso proposta
substituindo fat por sua definio
geral
Idem
Idem
Idem
Idem
usando a definio especfica
usando a primitiva de multiplicao
Idem
Idem
Idem
Idem

Surpreso(a)? Simples, no? assim mesmo, bem simples. A cada passo


vamos substituindo uma expresso por outra at que nada mais possa ser
substitudo. O resultado surgir naturalmente. Mais tarde voltaremos ao assunto.
16.5. RECURSO EM LISTAS: A esta altura deste curso j estamos certos que
o uso de lista indispensvel para escrever programas interessantes. Em vista
disso, nada mais bvio que perguntar sobre o uso de recurso em listas. Veremos
que o uso de definies recursivas em listas produz descries simples, precisas e
elegantes.
J est na hora de alertar que os valores sobre os quais aplicamos os
conceitos que queremos definir recursivamente possuem uma caracterstica
importantssima, eles em si so recursivos.
Por exemplo, qualquer valor pertencente aos naturais pode ser descrito a
partir da existncia do zero e da funo sucessor (suc). Vejamos como podemos
obter o valor 5:
5 = suc(suc(suc(suc(suc 0)))))
As listas so valores recursivos. Podemos descrever uma lista da seguinte
maneira:
Uma lista :
1. a lista vazia;
2. um elemento seguido de uma lista

1
28
Esta natureza recursiva das listas nos oferece uma oportunidade para, com
certa facilidade, escrever definies recursivas. A tcnica consiste basicamente
em:
1. Obter a definio geral: isto consiste em identificar uma
operao binria simples que possa ser aplicada a dois
valores. O primeiro deles o primeiro (head) da lista e o
outro um valor obtido pela aplicao do conceito em
definio ao resto (tail) da lista;
2. Obter a definio independente, que se aplicar base da
recurso. Esta, em geral, a lista vazia;
3. Garantir que a aplicao sucessiva do tail levar base da
recurso.
Na Figura 15.2 ilustramos o processo recursivo de obter listas cada vez
menores, atravs da aplicao da funo tail. Ao final do processo obteremos a
lista vazia ([ ]).
[xo, x1, x2, x3, x4 ... xn-1]

xo [x1, x2, x3, x4 ... xn-1]


x1 [x2, x3, x4 ... xn-1]
x2 [x3, x4 ... xn-1]

head

x3 [x4 ... xn-1]


x4 [... xn-1]

tail

...

xn-1 [ ]
Figura 15.2 componentes recursivos de uma lista
Exemplo 01 - Descrever o somatrio dos elementos de uma lista.
Soluo - Podemos pensar da seguinte maneira: o
somatrio dos
elementos de uma lista igual soma do primeiro elemento da lista como o
somatrio do resto da lista. Alm disso, o somatrio dos elementos de uma lista
vazia igual a zero.

1
29
somat [xo, x1, x2, x3, x4 ... xn-1]
xo + somat [x1, x2, x3, x4 ... xn-1]
X0 + x1 + somat [x2, x3, x4 ... xn-1]
X0 + x1 + x2 + somat [x3, x4 ... xn-1]
X0 + x1 + x2 + x3 + somat [x4 ... xn-1]
X0 + x1 + x2 + x3 + somat [x4 ... xn-1]
... [... x ]
X0 + x1 + x2 + x3 + x4 + somat
n-1
X0 + x1 + x2 + x3 + x4 + ... + xn-1+ somat [ ]
X0 + x1 + x2 + x3 + x4 + ... + xn-1 + 0
Figura 15.2 desenvolvimento da computao de
somatrio dos elementos de uma lista
Vejamos ento a codificao:
--- definio recursiva da somatria dos
-- elementos de uma lista
-somat xs = if null xs
then 0
else head xs + somat (tail xs)

A seguir alguns exemplos de uso:


Main> somat [4,5,2,7,9]
27
(52 reductions, 60 cells)
Main> somat [1..10]
55
(275 reductions, 421 cells)
Main> somat [1000,9999..1]
0
(45 reductions, 68 cells)
Main> somat [1000,999..1]
500500
(18051 reductions, 25121 cells)

Exemplo 02 - Descrever a funo que determina o elemento de valor


mximo uma lista de nmeros.
Soluo: O mximo de uma lista o maior entre o primeiro elemento da lista
e o mximo aplicado ao resto da lista. Uma lista que tem apenas um elemento tem
como valor mximo o prprio elemento (Figura 15.3).

1
30
maximo [xo, x1, x2, x3, x4 ... xn-1]
maior( xo , maximo [x1, x2, x3, x4 ... xn-1] )
maior( xo , maior(x1, maximo [x2, x3, x4 ... xn-1])) ))
maior( xo , maior(x1, maior(x2, maximo [x3, x4 ... xn-1] )))
maior( xo , maior(x1, maior(x2, maior(x3, maximo [x4 ... xn-1] ))))
maior( xo , maior(x1, maior(x2, maior(x3, maior(x4, ... maximo[xn-2 , xn-1])))))
maior( xo , maior(x1, maior(x2, maior(x3, maior(x4, ... maior(xn-2 , maximo[ xn-1])))))
maior( x15.3
, maior(x
, maior(x2, maior(x3,da
maior(x
, ... maior(x
x ))))))
Figura
desenvolvimento
computao
don-2 elemento
mximo
o
1
4
, n-1

de

uma lista

A definio recursiva apresentada a seguir:


--- definio recursiva do mximo de uma lista
-maximo xs = if null (tail xs)
then head xs
else maior (head xs) (maximo (tail xs))
-maior x y = if x > y then x else y

E vamos acompanhar agora algumas submisses:


Main> maximo [4,6,7,89,32,45,98,65,31]
98
(126 reductions, 150 cells)
Main> maximo ([1..1000]++[1500,1400..1])
1500
(31419 reductions, 44567 cells)
Main> maximo [100,(100 - k) .. 1] where k = 80
100
(91 reductions, 125 cells)

E agora uma surpresa.


Main> maximo [ ]
ERROR: Unresolved overloading
*** Type
: Ord a => a
*** Expression : maximo []

Voc consegue explicar?


Exemplo 03 - Descrever a funo que verifica se um dado valor ocorre em
uma lista tambm dada.

1
31
Soluo : Podemos pensar da seguinte maneira: Um dado elemento k
ocorre em uma lista se ele igual ao primeiro elemento da lista ou se ele ocorre
no resto da lista. Em uma lista vazia no ocorrem elementos quaisquer (Figura
15.4).

ocorre k [xo, x1, x2, x3, x4 ... xn-1]


k = xo | ocorre k [x1, x2, x3, x4 ... xn-1]
k = xo | (k = x1 | ocorre k [x2, x3, x4 ... xn-1])
k = xo | (k = x1 | ( k = x2 | ocorre k [x3, x4 ... xn-1]))
k = xo | (k = x1 | ( k = x2 | (k = x3 | ocorre k [x4 ... xn-1])))
k = xo | (k = x1 | ( k = x2 | (k = x3 | (k = x4 ) || ocorre k [... xn-1]))))
...
k = xo | (k = x1 | ( k = x2 | (k = x3 | (k = x4 ) | ... ocorre k [xn-1])))))
k = xo | (k = x1 | ( k = x2 | (k = x3 | (k = x4 ) | ... | (k = xn-1)| ocorre k [ ])))))

Figura 15.4 desenvolvimento da computao da ocorrncia de


um elemento em uma lista
Vejamos ento a codificao:
--- descreve a ocorrncia de dado k em uma lista xs
-ocorre k xs = if null xs
then False
else (k==head(xs)) || ocorre k (tail xs)

E algumas submisses:
Main> ocorre 5 [8,65,46,23,99,35]
False
(71 reductions, 111 cells)
Main> ocorre 5 [8,65,46,5,23,99,35]
True
(47 reductions, 58 cells)
Main> ocorre 5 [ ]
False
(16 reductions, 30 cells)

1
32
Exemplo 04 - Descrever a funo que obtm de uma lista xs a sublista
formada pelos elementos que so menores que um dado k :
Soluo : Precisamos descrever uma nova lista, vamos denomin-la de
menores, em funo de xs e de k. Quem ser esta nova lista? Se o primeiro
elemento de xs for menor que k, ento ele participar da nova lista, que pode ser
descrita como sendo formada pelo primeiro elemento de xs seguido dos menores
que k no resto de xs. Se por outro lado o primeiro no menor que k, podemos
dizer que a lista resultante obtida pela aplicao de menores ao resto da lista.
Novamente a base da recurso definida pela lista vazia, visto que em uma lista
vazia no ocorrem elementos menores que qualquer k.
A codificao apresentada a seguir:
--- define a lista de menores que um dado elemento em
-- uma lista dada
-menores k xs = if null xs
then xs
else if head xs < k
then head xs : menores k (tail xs)
else menores k (tail xs)

Desta podemos obter as seguintes avaliaes:


Main> menores 23 [8,65,46,5,23,99,35]
[8,5]
(122 reductions, 188 cells)
Main> menores 46 [8,65,46,5,23,99,35]
[8,5,23,35]
(135 reductions, 175 cells)
Main> menores 5 []
[]
(17 reductions, 24 cells)

16.6. EXPLORANDO REUSO: Segundo o Professor George Polya, aps concluir


a soluo de um problema, devemos levantar questionamentos a respeito das
possibilidades de generalizao da soluo obtida. Dentro deste esprito, vamos
explorar um pouco a soluo obtida para o problema descrito a seguir.
Exemplo 5 (Sub-lista de nmeros pares) : Dada uma lista xs, desejamos
descrever uma sublista de xs formada apenas pelos nmeros pares existentes em
xs.
Soluo: Devemos considerar, como no problema de encontrar a sublista
dos menores (Exemplo 4), a existncia de suas situaes:

1
33
1. O primeiro elemento da lista um nmero par, neste caso a sublista
resultante dada pela juno do primeiro com a sublista de pares existente
no resto da lista.
2. O primeiro no par. Neste caso a sublista de pares em xs obtida pela
seleo dos elementos pares do resto de xs.
Concluindo, tomemos como base da recurso a lista vazia, que obviamente
no contm qualquer nmero.
Eis a soluo em HUGS:
--- sublista de nmeros pares
-slpares xs = if null xs
then xs
else if even (head xs)
then head xs : slpares (tail xs)
else slpares (tail xs)

E a avaliao de algumas instncias:


Main> slpares [1..10]
[2,4,6,8,10]
(322 reductions, 438 cells)
Main> slpares [1,3..100]
[]
(962 reductions, 1183 cells)

Vamos agora, seguindo as orientaes do mestre Polya, buscar


oportunidades de generalizao para esta funo. Podemos fazer algumas
perguntas do tipo:
1. Como faria uma funo para determinar a sublista dos nmeros
mpares a partir de uma dada lista?
2. E se quisssemos a sublista dos primos?
3. E que tal a sublista dos mltiplos de cinco?
Uma breve inspeo na soluo acima nos levaria a entender que a nica
diferena entre as novas funes e a que j temos a funo que verifica se o
primeiro elemento satisfaz uma propriedade, no caso presente a de ser um
nmero par (even), conforme destacamos a seguir:

1
34
--- sublista de nmeros pares
-slpares xs = if null xs
then xs
else if even (head xs)
then head xs : slpares (tail xs)
else slpares (tail xs)
--- sublista de nmeros impares
-slimpar xs = if null xs
then xs
else if odd (head xs)
then head xs : slimpar (tail xs)
else slimpar (tail xs)
--- sublista de nmeros primos
-slprimo xs = if null xs
then xs
else if primo (head xs)
then head xs : slprimo (tail xs)
else slprimo (tail xs)

Isto nos sugere que a funo avaliadora pode ser um parmetro. Pois bem,
troquemos ento o nome da funo por um nome mais geral e adicionemos sua
interface mais uma parmetro. Este parmetro, como sabemos, dever ser do
tipo:

alfa -> Boolean


Vejamos ento o resultado da codificao, onde a propriedade a ser
avaliada se converte em um parmetro:
--- sublista de elementos de xs que satisfazem
-- a propriedade prop
-sublista prop xs = if null xs
then xs
else if prop (head xs)
then head xs : sublista prop (tail xs)
else sublista prop (tail xs)

Vejamos ento algumas aplicaes na nossa funo genrica para


determinar sublistas:

1
35
Main> sublista even [1..10]
[2,4,6,8,10]
Main> sublista odd [1..10]
[1,3,5,7,9]
Main> sublista (<5) [1..10]
[1,2,3,4]
Main> sublista (>=5) [1..10]
[5,6,7,8,9,10]

Observe que a funo que havamos anteriormente definido para determinar


os elementos menores que um certo valor k, da mesma forma que a funo para
determinar os maiores que k, est contemplada com a nossa generalizao. As
duas ltimas avaliaes no quadro acima ilustram a determinao da sublista dos
valores menores que 5 e a dos maiores ou iguais a 5.
Exerccios:
Descreva funes em HUGS que utilizem recurso para resolver os problemas
abaixo.
1. Obter a interseo de duas listas xs e ys.
2. Dadas duas strings xs e ys, verificar se xs prefixo de ys.
3. Dadas duas strings xs e ys, verificar se xs sufixo de ys.
4. Dadas duas strings xs e ys, verificar se xs sublista de ys.
5. inverter uma lista xs;
6. Definir a funo tWhile, que tenha o mesmo comportamento que a funo
takeWhile.
7. Definir a funo dWhile, que tenha o mesmo comportamento que a funo
dropWhile.
8. verificar se uma string um palndrome (a string a mesma quando lida da
esquerda para a direita ou da direita para a esquerda).
9. Verifique se uma string uma palavra. Defina uma palavra como formada
apenas por letras.
10. verificar se os elementos de uma lista so distintos.
11. determinar a posio de um elemento x em uma lista xs, se ele ocorre na
lista.
12. descrever a lista das palavras que existem no texto, dado um texto.
13. Dadas duas listas xs e ys, ordenadas em ordem crescente, obter a lista
ordenada resultante da intercalao de xs e ys.
14. calcular a combinao de uma lista xs, p a p.

1
36

17. ORDENAO RECURSIVA DE DADOS, ALGUNS PROBLEMAS


CORRELATOS E ALGUMAS TCNICAS DE PROPSITO GERAL
17.1 INTRODUO: Voltemos ento ao problema de ordenar os elementos de
uma lista, para o qual j discutimos uma soluo no paradigma aplicativo.
Dada uma lista xs desejamos descrever sua ordenao.
Vamos comear propondo e resolvendo um problema mais simples.
Insero ordenada: Dada uma lista ordenada xs e um elemento k
desejamos descrever uma lista a partir de xs, na qual esteja includo o valor k,
com a condio de que a nova lista tambm esteja ordenada.
Soluo : Voltemos a nossa estratgia para obter solues recursivas. Aqui
tambm temos dois casos:
1. O valor k menor que o primeiro da lista xs, neste caso a lista resultante
descrita pela juno de k com a lista xs;
2. O valor k maior ou igual ao primeiro elemento da lista xs, neste caso a
lista resultante descrita pela juno do primeiro da lista xs com a lista
obtida pela insero ordenada de k no resto da lista xs.

insord k Xs =

k < x0

k : Xs

Caso contrrio x0 : insord k Xs

Figura 17.1 insero ordenada de um


elemento k em uma lista Xs
A codificao pode ser realizada da seguinte forma:
--- insero ordenada de um valor k em uma
-- lista ordenada (no decrescente)
-insord k xs = if null xs
then [k]
else if k < head xs
then k : xs
else head xs : (insord k (tail xs))

1
37
E a seguir algumas aplicaes da soluo:
Main> insord 5 [0,2..10]
[0,2,4,5,6,8,10]
(230 reductions, 407 cells)
Main> insord 5 [10,15..50]
[5,10,15,20,25,30,35,40,45,50]
(248 reductions, 379 cells)
Main> insord 5 [-10,15..0]
[-10,5]
(92 reductions, 135 cells)
Main> insord 5 [-10,-5..0]
[-10,-5,0,5]
(154 reductions, 220 cells)
Main> insord 5 []
[5]
(23 reductions, 32 cells)

Agora j podemos voltar ao nosso problema inicial de ordenao de listas.


Vamos em busca de uma primeira soluo:
Soluo : A ordenao no decrescente de uma lista xs qualquer igual
insero ordenada do primeiro da lista na ordenao do resto da lista.
--- ordenao de uma lista
-ordena xs = if null xs
then xs
else insord (head xs) (ordena (tail xs))

Vejamos a aplicao da soluo algumas instncias:


Main> ordena [3, 4, 50,30,20,34,15]
[3,4,15,20,30,34,50]
(241 reductions, 330 cells)
Main> ordena [100,93..50]
[51,58,65,72,79,86,93,100]
(568 reductions, 780 cells)

1
38
17.2 DIVISO E CONQUISTA (UMA TCNICA PODEROSA): Alguns problemas
possuem solues mais facilmente descritas, algumas at mais eficientes, quando
quebramos o problema em partes menores, descrevemos a soluo de cada parte
e depois combinamos as solues parciais para obter a soluo completa. Este
mtodo denominado de "diviso e conquista". Basicamente buscamos encontrar
instncias do problema onde a soluo seja imediata. . Nesta seo veremos
alguns exemplos desta abordagem. O primeiro deles, a pesquisa binria, trata da
busca de um elemento em uma lista ordenada. Os outros dois, mergesort e
quicksort, apresentam solues alternativas para a ordenao de uma lista.
17.2.1. PESQUISA BINRIA - Voltemos a um problema j apresentado
anteriormente, verificao da ocorrncia de um elemento a uma lista. Segundo a
definio que apresentamos para a funo ocorre, apresentada no exemplo 3 do
Captulo 16. Podemos constatar que para avaliar expresses onde o elemento
procurado no ocorre na lista, o avaliador de expresses precisar fazer uma
quantidade de comparaes igual ao comprimento da lista considerada. Na mdia
de um conjunto de avaliaes, considerando as avaliaes de expresses em que
o elemento procurado est na lista, e que a cada vez estaremos procurando por
um elemento distinto, teremos um nmero mdio de comparaes da ordem de
(n / 2). Se n for muito grande ficaremos assustados com o nmero de
comparaes. Por exemplo, para uma lista de 1000000 (um milho) de elementos,
em mdia teremos que fazer 500 mil comparaes.
Se pudermos garantir que a lista est ordenada, ento podemos fazer uso de
uma estratgia j discutida anteriormente para reduzir este nmero. Estamos
falando da rvore binria de pesquisa. A estratgia que usaremos consiste em, a
cada passo de reduo, abandonarmos metade da lista considerada a partir da
comparao de k com o elemento que se encontra na metade da lista. Se o
elemento buscado (k) for igual ao elemento central, ento o processo de avaliao
est encerrado. Quando isto no ocorre, devemos ento escolher em qual lista
devemos procur-lo. Quando ele menor que o elemento central devemos busclo na sublista que antecede o central, caso contrrio devemos busc-lo na sublista
dos seus sucessores. Novamente a base da recurso determinada pela lista
vazia.
Nesta abordagem, a cada escolha abandonamos metade da lista restante.
Desta forma, o nmero de comparaes dado pelo tamanho da seqncia:
n/1, n/2, n/4, ... , n/n
Para simplificar a anlise podemos escolher um n que seja potncia de 2.
Neste caso podemos assegurar que o comprimento da seqncia dado por:
Log n na base 2

1
39
Voltando ento ao nmero de comparaes necessrias para localizar um
elemento, podemos constatar que em uma lista com 1 milho de elementos, ao
invs das 500 mil comparaes da soluo anterior, precisaremos no pior caso, de
apenas 20 comparaes. Isso mesmo, apenas 20.
Vamos ento codificao em HUGS:
--- pesquisa binria
-pesqbin k xs = if null xs
then False
else if k == pivot
then True
else if k < pivot
then pesqbin k menores
else pesqbin k maiores
where
p
= div (length xs) 2
menores = take p xs
maiores = tail (drop p xs)
pivot
= head (drop p xs)

E a seguir, a avaliao de algumas instncias:


Main> ocorre 1023 [0..1023]
True
(24592 reductions, 32797 cells)
Main> pesqbin 1023 [0..1023]
True
(71563 reductions, 92060 cells)

17.2.2 MERGESORT - Existem outras maneiras de se descrever a ordenao de


uma lista. Uma delas, denominada mergesort, se baseia na intercalao de duas
listas j ordenadas. Comecemos ento por discutir a intercalao que, em si
mesmo, j representa uma ferramenta intelectual bastante interessante.
Intercalao: Antes de ver o mergesort podemos apresentar uma verso
recursiva para a intercalao de duas listas em ordem no decrescente.
Soluo: A intercalao de duas listas ordenadas xs e ys pode ser descrita
atravs de dois casos:
1. se o primeiro elemento de xs menor que o primeiro elemento de
ys ento a intercalao dada pela juno do primeiro elemento de
xs com a intercalao do resto de xs com ys;
2. caso contrrio, a intercalao descrita pela juno do primeiro
elemento de ys com a intercalao do resto de ys com xs;

1
40
A codificao resultante pode ser observada a seguir:
--- Intercala duas listas em ordem no decrescente
-intercala xs ys = if (null xs) || (null ys)
then xs ++ ys
else if head xs <= head ys
then head xs : intercala (tail xs) ys
else head ys : intercala xs (tail ys)

E a seguir, algumas submisses e avaliaes do HUGS:


Main> intercala [1,3..10] [0,2..10]
[0,1,2,3,4,5,6,7,8,9,10]
Main> intercala [0,2..10] [1,3..10]
[0,1,2,3,4,5,6,7,8,9,10]
Main> intercala [0,2..10] []
[0,2,4,6,8,10]
Main> intercala [] []
ERROR: Unresolved overloading
*** Type
: Ord a => [a]
*** Expression : intercala [] []
Main> intercala [] [0,2..10]
[0,2,4,6,8,10]
Main> intercala [0,2..10] [0,2..10]
[0,0,2,2,4,4,6,6,8,8,10,10]
Main> intercala [9,7..1] [10,8..1]
[9,7,5,3,1,10,8,6,4,2]
(o que houve que no ficou ordenada?)

Voltemos ao mergesort, ou, em bom portugus, ordenao por intercalao.


Soluo : A ordenao de uma lista por mergesort igual intercalao do
mergesort da primeira metade da lista com o mergesort da segunda metade. Esta
soluo explora a noo de rvore binria. Neste caso, a lista original dividida
em 2 partes, cada uma delas em outras duas e assim sucessivamente at que
esta quebra no seja mais possvel. A figura Fig. 17.1 ilustra o processamento da
ordenao de uma lista.

1
41

Vejamos ento como fica a codificao em HUGS.


--- ordena uma lista pela intercalao da ordenao de
-- suas duas metades
-mergesort xs = if null (tail xs)
then xs
else intercala (mergesort m) (mergesort n)
where
m = take k xs
n = drop k xs
k = div (length xs) 2

1
42
Main> mergesort [1..10]
[1,2,3,4,5,6,7,8,9,10]
(1593 reductions, 2185 cells)
Main> mergesort [10,9..1]
[1,2,3,4,5,6,7,8,9,10]
(1641 reductions, 2236 cells)

17.2.3. QUICKSORT - Existe uma maneira muito famosa de resolver o


mesmo problema de ordenao, usando ainda a noo de diviso e conquista,
muito parecida com o mergesort. Implementaes desta soluo reduzem
sensivelmente o nmero de comparaes necessrias e so, portanto muito
utilizadas.
Soluo : Na verso usando o mergesort dividamos a instncia original
exatamente ao meio. Nesta vamos dividir tambm em duas, mas com seguinte
critrio: a primeira com os elementos menores que um elemento qualquer da lista
e a segunda com os elementos maiores ou iguais a ele. Este elemento
denominado pivot e existem vrias formas de escolh-lo. A melhor escolha
aquela que produzir as sublistas com comprimentos bem prximos, o que
repercutir no desempenho da avaliao. Aqui nos limitaremos a escolher como
pivot o primeiro elemento da lista. Assim sendo, aps obter a ordenao das duas
listas, basta juntar a ordenao da primeira, com o pivot e finalmente com a
ordenao da segunda. A figura Fig. 9.2 ilustra a aplicao do quicksort a uma
instncia do problema.

1
43

E a seguir vejamos a codificao.


quicksort xs = if (null xs) || (null (tail xs))
then xs
else
quicksort (sublista (< pivot) (tail xs))
++ [pivot]
++ quicksort (sublista (>= pivot) (tail xs))
where
pivot = head xs

Convidamos o leitor a apreciar e discutir a elegncia, a compacidade e a


clareza da descrio do quicksort.

1
44
Vejamos a avaliao de algumas instncias:
Main> quicksort [4,5,6,7,8,3,2,1]
[1,2,3,4,5,6,7,8]
(595 reductions, 755 cells)
Main> quicksort [1..10]
[1,2,3,4,5,6,7,8,9,10]
(1536 reductions, 1881 cells)
Main> quicksort [10,9..1]
[1,2,3,4,5,6,7,8,9,10]
(1541 reductions, 1952 cells)
Main> mergesort [10,9..1]
[1,2,3,4,5,6,7,8,9,10]
(1647 reductions, 2283 cells)
Main> mergesort xs == quicksort xs where xs = [1..10]
True
(2805 reductions, 3563 cells)
Main> mergesort [2,14,16,23,29,35,47,68,70,90]
[2,14,16,23,29,35,47,68,70,90]
(1414 reductions, 1922 cells)
Main> quicksort [2,14,16,23,29,35,47,68,70,90]
[2,14,16,23,29,35,47,68,70,90]
(1357 reductions, 1618 cells)
Main> ordena [2,14,16,23,29,35,47,68,70,90]
[2,14,16,23,29,35,47,68,70,90]
(236 reductions, 336 cells)

17.3. PROCESSAMENTO DE CADEIAS DE CARACTERES: As cadeias de


caracteres, como j vimos, tambm so listas, portanto o uso de recurso com
cadeias segue as mesma recomendaes. Para ilustrar vamos apresentar alguns
exemplos.
Exemplo 01 - [Palndromo] Dada uma cadeia de caracteres verifique se
um palndromo. Segundo o dicionrio, um palndromo uma frase ou palavra, que
no importando o sentido que se l, significa a mesma coisa. Por exemplo,
"Socorram-me subi no nibus em Marrocos". Vejam que a quantidade de
espaos, os separadores e os trminos de palavra no so considerados. Aqui
vamos tratar a questo de forma simplificada, os separadores sero tratados como
caracteres comuns.
Soluo : Neste caso, importante observar que podemos olhar a cadeia
como sendo formada por pares de valores eqidistantes dos extremos. Um cadeia
palndromo se os seus extremos so iguais e o meio da lista um palndromo. A
base da recurso so as cadeias vazias ou aquelas com apenas um elemento.

1
45
palndromo [x0, x1, x2, x3, x4, x5, ..., x n-1]
x0 = x n-1 & palndromo [x1, x2, x3, x4, x5, ..., ]
x0 = & (x1 = x n-1 & palndromo [ x2, x3, x4, x5, ..., ] )
x0 = & (x1 = x n-1 & ( X2 = Xn-2 & palndromo [x3, x4, x5, ..., ] ))
Figura 17.1 desenvolvimento da computao da funo
palndromo

Vejamos ento a codificao em HUGS e a avaliao para algumas


instncias.
E agora uma avaliao de algumas listas candidatas a palndromo:
--- Verifica se uma sentena Palndromo
--palindromo xs = if null xs || null (tail xs)
then True
else (head xs == last xs) &&
palindromo (meio xs)
where
meio xs = init (tail xs)

Seguindo nosso padro de apreentao,vejamos como ficam algumas


avaliaes:
Main> palindromo "socorrammesubinoonibusemmarrocos"
True
(687 reductions, 698 cells)
Main> palindromo "socorram-me subi no onibus em marrocos"
False
(891 reductions, 907 cells)
Main> palindromo "ama"
True
(31 reductions, 43 cells)
Main> palindromo "papagaio"
False
(29 reductions, 45 cells)
Main> palindromo "arara"
True
(49 reductions, 61 cells)

1
46
Exemplo 02 - [Prefixo] Dadas duas cadeias de caracteres verifique se a
primeira idntica subcadeia formada pelos primeiros caracteres da segunda.
Por exemplo, "aba" prefixo da cadeia "abacaxi" e "pre" prefixo de "prefixo".
Soluo : De imediato podemos dizer que uma cadeia xs prefixo de uma
cadeia ys quando:
i)
ii)
iii)

o primeiro elemento de xs igual ao primeiro elemento de ys e;


o restante de xs prefixo do restante de ys.

Quanto base da recurso, temos que considerar duas situaes:


i)
ii)

A primeira tem como base que a cadeia vazia prefixo de qualquer


outra cadeia;
A segunda leva em conta que nenhuma cadeia pode ser prefixo de uma
cadeia vazia (exceto a cadeia vazia).
Vejamos como fica em Haskell:
--- Verifica se uma cadeia xs prefixo
-- de uma segunda (ys)
-prefixo xs ys = if null xs
then True
else if null ys
then False
else (head xs == head ys) &&
prefixo (tail xs) (tail ys)

As avaliaes de expresses a seguir nos permitem observar o


funcionamento de nossa descrio:
Main> prefixo "aba" "abacadraba"
True
Main> prefixo "" "abacadraba"
True
Main> prefixo "pre" "prefixo"
True
Main> prefixo "prefixo" "pre"
False
Main> prefixo "prefixo" ""
False

1
47
Exemplo 03 - [Casamento de Padro] Verificar se uma cadeia satisfaz um
determinado padro um processamento muito til e constantemente realizado na
prtica da computao. Aqui nos ateremos a uma forma simplificada deste
problema que consiste em verificar se uma cadeia subcadeia de outra.
Soluo : Uma rpida inspeo nos leva constatao de que o problema
anterior parecido com este, exceto pelo fato de que a primeira cadeia pode
ocorrer em qualquer lugar da segunda. Podemos dizer ento que a primeira
cadeia ocorre na segunda se ela um prefixo da primeira ou se ela ocorre no
resto da segunda.
Vejamos como fica em HUGS:
--- Verifica se uma cadeia
-- de uma outra (ys)
-subcadeia xs ys = if null
then
else

xs subcadeia
ys || null (tail ys)
False
prefixo xs ys || subcadeia xs (tail ys)

A avaliao das expresses a seguir ajuda no entendimento:


Main>
True
Main>
True
Main>
True
Main>
True
Main>
False
Main>
False

subcadeia "" "prefacio"


subcadeia "pre" "prefacio"
subcadeia "cio" "prefacio"
subcadeia "efa" "prefacio"
subcadeia "acido" "prefacio"
subcadeia "efa" ""

Exerccios:
i)
ii)
iii)
iv)
v)
vi)

Jonoihoi
Ionoihno
Noinboiho
Oioho[
Oihnoihjo
Oinoihjpo

1
48

18. EXERCCIOS COMPLEMENTARES


Apresentamos a seguir alguns exerccios que visam suprir material para o leitor
que desejar praticar um pouco mais com a programao atravs de descries
funcionais.
Para cada um dos problemas a seguir d uma descrio funcional na linguagem
Haskell.
Sugerimos que o leitor edite as definies em um arquivo de scripts e use essas
definies em alguns exemplos para certificar-se se suas definies esto
corretas. Para cada funo elabore uma planilha de teste, indicando os valores
para os quais as mesmas sero avaliadas e quais os resultados esperados, insira
a planilha como comentrio, conforme se ilustra a seguir.
Exemplo :
Descrio do problema: Dados dois nmeros a e b mapeie-os no maior deles.
Soluo:
-- def : mapeia dois nmeros a e b no maior deles
-- teste : maior 3 4 ==> 4; maior 4 3 ==> 4; maior 3 3 ==> 3
maior a b = if a > b then a else b
18.1 Grupo I Problemas Gerais
1. Dados quatro nmeros p1, p2, p3 e p4, mapeie-os na sua soma se a diviso
desta soma por 5 exata e em zero caso contrrio.
2. Dado um nmero inteiro, verifique se ele pertence ao intervalo (0,100) e
divisvel por 3 e por 5.
3. O operador || (OU inclusivo), provido pelo Hugs, mapeia dois valores
booleanos a e b em True quando pelo menos um deles True e em False
caso contrrio. Escreva uma funo que denominaremos de oux (OU
exclusivo) que se assemelha ao OU inclusivo mas que mapeia em False
quando ambos valores so True.
4. Dados 3 valores a, b e c determine a mdia aritmtica dos valores extremos.
? media 10 35 4
19.5
? media 50 10 8
29

1
49
5. Dados trs nmeros inteiros distintos, calcule o quadrado do sucessor do maior
nmero.
6. Dados 3 pontos p1, p2 e p3, do plano cartesiano, determine se eles formam
um tringulo, e se for o caso,determine sua rea.
7. A empresa LucroCerto decidiu dar aos seus funcionrios um abono de Natal. A
gratificao ser baseada em dois critrios: o nmero de horas extras
trabalhadas e o nmero de horas que o empregado faltou ao trabalho. O
critrio estabelecido para calcular o prmio : subtrair dois tros das horas
que o empregado faltou de suas horas extras, obtendo um valor que determina
o nmero de pontos do funcionrio. A distribuio do prmio feita de acordo
com a tabela abaixo.
Pontos Obtidos
Prmio em R$

de

41

...

500,00

31

40

400,00

21

30

300,00

11

20

200,00

10

100,00

8. Considere dois pontos p1 e p2 no plano cartesiano. Estamos interessados em


identificar as seguintes relaes entre eles:
i. por p1 e p2 podemos traar uma reta paralela ao eixo horizontal;
ii. por p1 e p2 podemos traar uma reta paralela ao eixo vertical;
iii. p1 e p2 esto no mesmo quadrante;
iv. p1 e p2 esto em quadrantes diferentes;
v. p1 e p2 esto em quadrantes opostos (1 e 3 ou 2 e 4);
vi. p1 e p2 esto em quadrantes adjacentes (1-2, 2-3, 3-4, 1-4);
9. Dados dois pontos no plano cartesiano, eles podem ser idnticos, podem
determinar uma reta paralela a um dos dois eixos, ou determinar uma reta que
corta os dois eixos. Determine qual o caso em que dois dados pontos se
enquadram e, se ocorre o terceiro, qual a rea do tringulo determinado pela
reta e os eixos.
10. Dados um segmento de reta r, atravs de dois pontos, a e b, localizados no
primeiro quadrante, e um ponto p qualquer, determine se p pertence ao
segmento, ou se p pertence ao prolongamento de r, ou ainda se p est acima
da reta ou se p est abaixo.

1
50
11. Dados o canto superior esquerdo e o canto inferior direito de um retngulo R,
paralelo aos eixos, determine quantos quadrantes so cobertos por ele.
12. Dados dois retngulos, paralelos aos eixos, determine se h ou no interseo
entre eles. Determine ainda, se for o caso, a rea de interseo entre dois
retngulos.
13. Considere um retngulo definido por seus cantos superior esquerdo e inferior
direito. Podemos traar um losango a partir de pontos localizados no ponto
mdio de cada um de seus lados. Definimos com isso seis regies.
i. fora do retngulo;
ii. o tringulo superior esquerdo;
iii. o tringulo superior direito;
iv. o tringulo inferior direito;
v. o tringulo inferior esquerdo;
vi. o interior do losango.
vii. Dado um ponto p, determine a sua localizao.
viii.
14. Dados 3 nmeros, determine se com os trs eu posso formar uma progresso
aitimtica (PA), onde dois deles quaisquer so termos consecutivos e um
terceiro a razo.
15. Dados 3 nmeros, determine se com os trs eu posso formar uma progresso
gepmtrica (PG), onde dois deles quaisquer so termos consecutivos e um
terceiro a razo.
16. Considere que o preo de uma passagem de avio em um trecho, pode variar
dependendo da idade do passageiro. Pessoas com 60 ou mais anos de idade
pagam apenas 60% do preo total. Crianas at 10 anos, pagam 50% e bebs
(abaixo de 2 anos) pagam apenas 10%. Escreva uma definio que tenha
como entrada o valor nominal da passagem e a idade do passageiro e produz
o valor a ser pago.
17. Dados dois nmeros inteiros, considere que eles possuem no mximo 5
algarismos. Determine em que quantidade de algarismos na mesma posio
eles so iguais.
?qalg 123 124
2
?qalg 1234 4321
0

1
51
18. Dados dois pontos p e q, no plano cartesiano, tome a origem dos eixos como o
eixo dos ponteiros de um relgio analgico, p como a posio da extremidade
do ponteiro maior e q como a do ponteiro menor. Determine a quantidade total
de minutos decorridos desde o incio do dia.
19. Dados trs nmeros a, b, c. Determine quais das seguintes relaes eles
mantm entre si: a) os trs so diferentes; b) apenas dois so iguais; c) os trs
so iguais.
20. Considere que um dado nmero inteiro est armazenando um valor v escrito
na base octal. Pede-se: a) verifique se realmente o nmero dado est na base
8; b) determine qual o valor deste nmero na base decimal.
21. Considere um tabuleiro de xadrez de dimenses infinitas, considere ainda que
a numerao das casas dada por um par de nmeros inteiros. Sabemos que
o cavalo possui oito movimentos conforme a figura 3.
m3

M3

m2

m4

m1
C

m5

m8
m6

m7

Escreva uma funo para determinar a nova posio obtida pela aplicao de
cada movimento posio X. O resultado dever ser produzido com um nmero
de 2 casas.

18.2 Grupo 2 Geomtricos I


Dado um ponto P(x,y) do plano cartesiano, defina funes que descrevam a sua
pertinncia nas situaes abaixo especificadas:
1. Um retngulo (com lados paralelos aos eixos cartesianos) dado pelas
coordenadas do canto superior esquerdo e do canto inferior direito, como
mostrado na figura.

1
52

2. Um losango , com os seus eixos paralelos aos eixos cartesianos, dado pelas
coordenadas do vrtice esquerdo e do vrtice superior, como mostrado na
figura.

3. Um crculo dado pelo seu centro C e seu raio r.

4. A regio R1 (regio cinza), do retngulo dado pelas coordenadas do canto


superior esquerdo e do canto inferior direito, como mostrado na figura abaixo:

5. A regio R2 do losango (regio cinza), sendo dados os pontos E e D do


retngulo e sabendo-se que o crculo tangente aos lados do losango.

1
53

18.3 Grupo 3 Geomtricos II


Resolva os problemas abaixo priorizando o uso de modularizao. Procure
tambm utilizar quando for adequado, o conceito de definio local atravs da
clusula where.
1. Considere a figura e descreva uma funo para calcular cada uma das reas
da regies R1, R2 e R3. A funo tem como parmetros as coordenadas dos
pontos P (x1, y1) e Q (x2,y2). Observe que o ponto Q o centro do crculo,
que a altura do tringulo issceles igual ao raio do crculo e que um dos
lados do tringulo paralelo ao eixo dos x.

Y
Q

R3

y2

y1

R1
x1

R2
2

x2

R1
X

2. Dada uma reta descrita por dois pontos P (x1, y1) e Q (x2,y2), escreva uma
funo que determine o valor da coordenada no eixo dos y a partir de uma
coordenada fornecida no eixo dos x.
coordy x1 x2 y1 y2 x = ...
3. Considere a figura 2 e descreva uma funo para determinar cada uma das
reas das regies R1, R2 e R3. A funo tem como parmetros as
coordenadas dos pontos P e Q. Observe que um dos lados do tringulo
issceles coincide com o eixo dos x e que um dos seus vrtices a origem.
Observe ainda que os lados do retngulo so paralelos aos eixos.

1
54

Y
y1
R2
R11

y2
R3
x1

x2

4. Considere um pea de altura h cuja base e o topo so hexgonos de lado l.


Considere ainda que esta pea possui um furo cilndrico de raio r com centro
no eixo. Descreva uma funo para determinar o volume da pea.

5. Considere uma pea cilndrica com raio r e altura h. Considere ainda que esta
pea possui um furo em forma hexagonal de lado l, com centro no eixo da
pea. Descreva uma funo para determinar o volume da pea.

1
55
6. Considera a figura abaixo, onde est representada a regio R correspondente
a interseo de dois crculos de mesmo raio r. Escreva uma funo para
calcular a rea dessa regio, sabendo-se que dado o ngulo do setor do
crculo determinado pelos pontos de interseo das duas circunferncias.

r
R

7. Descreva uma funo que calcule a rea (representada pela cor cinza) de uma
flor formada por quatro crculos de mesmo raio r, cujos centros so os vrtices
de um quadrado, conforme ilustrado na figura a seguir. O miolo da flor um
crculo oco de raio r1.

18.4 Grupo IV - Geomtricos 3


1) Problemas de pertinncia de um ponto P (x,y) nas regies hachuradas,
utilizando expresses lgicas.
a) Descrio da regio hachurada: o centro C (c1, c2) e o raio r do crculo
maior so dados. Considera-se tambm que os raios dos crculos inscritos
so r/3 e 2r/3.

1
56
b) Descrio da regio hachurada: seja E (x1, y1) o vrtice superior esquerdo
de um quadrado de lado a paralelo aos eixos cartesianos. Considere que as
ptalas da flor so formadas por semi-crculos de raio a/2 e centros no
ponto mdio de cada lado do quadrado e que o miolo formado por dois
crculos de raios a/4 e a/8.
E

a/2
a/8
a/4

c) Descrio da regio hachurada: o centro C (c1, c2) e o raio r do crculo


maior so dados. Considera-se tambm que os raios dos crculos inscritos
so r/2 e r/4.

1
57
2) Problemas de mapeamento de um ponto P (x,y) em sua regio de pertinncia,
utilizando descries condicionais, de forma adequada.
a) Sejam E (x1, y1) e S (x2, y2) os vrtices esquerdo e superior,
respectivamente, de um losango cujos eixos so paralelos aos eixos
cartesianos. Considere as regies descritas abaixo:
regio 1: regies hachuradas, externas
losango, no
crculo superior
regio 2 : regies hachuradas, interna
losango, no
crculo superior
regio 3 : no losango e fora dos ciculos
regio 4: regies hachuradas, externas
losango, no
crculo inferior
regio 5 : regies hachuradas, interna
losango, no

ao
ao

ao
ao

b) So dados os pontos E (x1, y1) e D (x2, y2) e sabe-se que o raio dos semicrculos extermos igual (y1 - y2 ) /2.

1
58
19. APLICAES
Neste captulo apresentamos uma srie temtica de exerccios, buscando dar ao
leitor uma viso mais ampla das possibilidades de uso da programao funcional.
A inteno apresentar vrios contextos onde precisamos programar
computadores. Em todos, o contexto descrito e vrios exerccios so
apresentados. Aos professores e estudantes, sugerimos que o contexto sirva de
pretexto para a formulao e resoluo de novos exerccios. Comeamos pelo
Domin Bar, onde, buscamos na ludicidade do jogo, apresentar as
necessidades de manipular informao. Na seqncia apresentamos uma srie de
problemas considerando as necessidades de informao de um Banco de
Sangue, o manuseio de mensagens de um Correio Eletrnico, a organizao de
uma Lista de Compras, um sistema de Passagens Areas, Gerncia
Acadmica, Agncia de Turismo e exerccios sobre Espetculos Teatrais.
19.1 O DOMIN BAR: O domin de nmeros uma coleo de pedras, utilizado
na maioria das vezes como um excelente passatempo. Das tantas formas de
utilizar o domin, destacamos uma, utilizada no Amazonas, principalmente em
Manaus, mas tambm em muitas praias pelo mundo afora onde existirem
amazonenses, em particular nas praias de Fortaleza. Os Amazonenses costumam
cham-la de domin bar", em homenagem a uma tribo que habitava a regio
onde foi fundada a cidade de Manaus. A maioria dos exerccios deste captulo
foram desenvolvidos em Manaus, no final da dcada de 80. De l pra c, vrios
outros foram acrescentados, mas a lista como um todo permanece indita.
A inteno desta seo apresentar alguns poucos exerccios resolvidos e propor
outros. A idia no desenvolver o jogo e sim, inspirar-se em situaes do jogo
para propor exerccios interessantes e desafiadores. Deixamos o desenvolvimento
do jogo completo como sugesto para o trabalho em grupos. Ao final do captulo
discutiremos um pouco sobre a programao do jogo.
Preliminares: O material do jogo um conjunto formado por 28 "peas", cada
uma delas com duas "pontas". Cada "ponta" representa um valor de 0 (zero) a
seis (6), perfazendo portanto 7 valores diferentes. Cada valor possui um nome
prprio: o Zero chama-se "branco", o um chama-se "s", o dois o "duque", o trs
chama-se "terno", o quatro a "quadra", o cinco a "quina" e o seis denomina-se
"sena". O nome de uma "pedra" dado pelo nome de suas "pontas", por exemplo,
"quina e terno", o nome da "pedra" que possui em uma ponta o valor 5 e na
outra o valor 3. As pedras que possuem o mesmo valor nas duas pontas so
denominadas de "carroa". Para cada tipo de valor existem 7 pedras, por exemplo,
para o "terno" teremos: terno e branco, terno e s, terno e duque, carroa de
terno, quadra e terno, quina e terno, sena e terno. O jogo , em geral, disputado
por duplas, ganhando a que fizer o maior numero de pontos, a partir de um
mnimo pr-estabelecido.
A seguir apresentamos em detalhes os vrios
elementos do jogo.

1
59
Peas do Jogo: Os elementos do jogo so (28) vinte e oito peas, cada uma com
duas pontas, na qual marcado um valor que varia de 0 a 6. Para jogar, as
"pedras" so embaralhadas e escolhidas pelos jogadores. A cada jogador cabem
7 pedras. Com o desenrolar do jogo a quantidade de pedras vai sendo decrescida,
at que, eventualmente chegue em zero.
Participantes: duas duplas (eventualmente pode ser jogado individualmente, com
2, 3 ou 4 jogadores).
Objetivo: atingir um total mnimo de 200 pontos. Vence o jogo a dupla que ao final
de uma rodada tiver o maior nmero de pontos.
Dinmica: o jogo se desenvolve em uma quantidade qualquer de eventos
menores denominados de rodada. A figura 18.1 ilustra um instante de jogo.

Figura 18.1 um instante do jogo de domin, com quatro pontas abertas:


terno, s, duque e quadra.

Rodada: em uma rodada, um aps o outro, no sentido horrio, os jogadores vo


fazendo suas jogadas, combinando suas pedras de domin com a figura que j
est formada na mesa de jogo.

1
60
Pontuao: existem 4 formas para obter pontos:
1. Durante o jogo, a figura formada na mesa possui 1 (quando existe apenas
uma pea assentada), 2, 3 ou 4 pontas. soma dos valores dessas pontas
denomina-se de: os pontos da mesa. Quando essa soma produz um
mltiplo de 5, o jogador que sentou a ltima pedra pode requerer que eles
sejam anotados em favor de sua dupla. Veja que s o jogador que sentou a
pedra pode reivindicar os pontos e isto tem que ocorrer antes que o
prximo jogador sente a sua pedra;
2. Quando um jogador no possui pedra para colocar na mesa (ou seja, uma
que combine com uma das pontas), ele passa a vez, e a dupla adversria
ganha 10 pontos. Se um jogador percebe que com a colocao de sua
pea ele conseguir fazer com que todos os demais passem, inclusive o
seu parceiro, ele pode anunciar que deu um passe geral e com isso ganhar
de bnus 50 pontos.
3. Quando um jogador descarta sua ltima pea em uma rodada diz-se que
ele bateu, e, portanto ganhou a rodada. Com isso ele ganha de bnus 10
pontos e mais o mltiplo de 5 ligeiramente inferior soma dos valores
constantes nas peas que sobraram nas mos dos adversrios (garagem).
Se a batida for feita com uma carroa, o bnus de 20 pontos.
4. Quando ocorre uma situao onde nenhum dos jogadores consegue jogar,
embora estejam com peas na mo, diz-se que o jogo est fechado. Neste
caso ganha a rodada a dupla cuja soma dos valores das peas for o menor.
A soma das peas da dupla adversria computada em seu favor, como no
caso 3.
Posio dos Jogadores: Os membros de cada dupla so colocados em posies
alternadas, de forma que as jogadas (colocao de peas) seja feita de forma
alternada entre as duplas adversrias. Por exemplo, em um jogo presencial,
podemos usar, como suporte para colocao das peas, uma mesa de quatro
lugares, ficando os parceiros sentados frente-a-frente.
Distribuio das Peas: a distribuio das 28 peas entre os 4 jogadores deve
ser feita de forma aleatria. Na prtica, em um jogo com peas fsicas, viram-se as
peas de cara para baixo e mistura as peas com as mos. Cada jogador vai
retirando as suas prprias peas.
Quem comea uma rodada: Uma rodada sempre iniciada com a colocao de
uma carroa. Na primeira rodada do jogo, a carroa a ser utilizada de sena (6),
cabendo pois ao jogador que a tirou comear o jogo. As rodadas seguintes so
iniciadas pelo jogador que bateu a rodada anterior, com a carroa que ele preferir.
Se ele no possui carroa, ele passa e o jogador seguinte (da dupla adversria)
inicia o jogo, se este tambm no possuir, passa a frente.
Uma Jogada: Estando na sua vez de jogar, o jogador deve escolher uma das
pedras de sua mo, e coloca-la na mesa de jogo, combinando com alguma das
pontas abertas. A escolha da pea a ser jogada deve contribuir para o objetivo da
dupla que ganhar o jogo, isso significa, em linhas gerais, escolher uma pedra

1
61
que me permita fazer o maior nmero de pontos e, quando isso no for possvel,
escolher uma pedra que reduza o nmero de pontos que os adversrios possam
fazer com base em minha jogada. H, entretanto algumas nuances a serem
consideradas:

Quando eu jogo fazendo pontos devo buscar maximizar meus pontos e


minimizar os que o jogador adversrio possa fazer a partir da minha jogada;

Se o jogo estiver prximo do trmino, e a dupla adversria ameaa


completar os 200 pontos, pode ser desejvel adiar o trmino, no fazendo
os pontos. Por exemplo, suponha que a dupla adversria tem 185 pontos e
a minha 130. Se eu tiver uma pea na mo que faz 25 pontos, mas se
possvel ao adversrio possuir uma pea que lhe permita fazer 15 pontos,
eu posso escolher outra pea, deixando assim de obter os 25 pontos;

Quem abre uma rodada, bater a rodada a menos que passe. Tendo em
vista que ao ganhar uma rodada, h bnus para a dupla, posso deixar de
marcar ponto visando vencer a rodada;

Idem para tentar evitar que a dupla adversria ganhe a rodada (quando
foro a passada de um adversrio que comeou a rodada, a batida passa
para o meu parceiro).

Um passe geral d um bnus de 50 pontos, isso pode me levar a busc-los,


desde que as condies do jogo, definidas pelas peas de minha mo,
combinadas com o que j foi jogado, se mostrem propcias.

Exerccios: A seguir apresentamos alguns exerccios, baseados no domin. Para


fins didticos separamos em grupos.
Grupo I
1. Escreva a funo pedrap que associe um par a True se e somente se (sss)
o par uma representao vlida para uma "pedra" e False caso contrrio.
Exemplos de uso:
1. pedrap (2, 7) ==> False
2. pedrap ((-3), 4) ==> False
3. pedrap (3,4) ==> True
Soluo:
pedrap (x,y) = validap x && validap y
validap x
= elem x [0..6]
2. Escreva a funo maop que associe uma lista de pares de inteiros a True
sss a lista uma representao vlida para a "mo" de um jogador e False
caso contrrio.

1
62
Exemplos de uso:
1.
2.
3.
4.

maop [ ] True
maop [((-3), 4)] False
maop [(3,4)] True
maop [ (1,2), (1,5), (2,0), (2,4), (3,3), (1,1), (0,0), (4,0)] False

Soluo:
maop [ ]
= True
maop (x:xs) = (length xs <= 6) && pedrap x && maop xs

3. Escreva a funo carrocap que associe um par a True sss o par uma
"carroa" e False caso contrrio.
4. Escreva a funo tem_carroca_p que associe uma "mo" a True sss a
mo possuir pelo menos uma carroa e False caso contrrio.
5. Escreva a funo tem_carrocas que associe a uma "mo" a lista das
"carroas" nela contida.
Grupo II
Em vrios momentos do jogo faz-se necessrio saber a quantidade de pontos
associado uma coleo de pedras. Em particular, no final do jogo, quem
"sentou" a sua ltima pedra faz jus "garagem" que determinada a partir dos
pontos que restaram na(s) mo(s) dos adversrios.
6. Escreva a funo pontos que associe uma lista de "pedras" a soma dos
pontos das pedras nela contidos. Onde os pontos de uma pedra a soma
de suas pontas.
Soluo:
pontos [ ]
=0
pontos (x:xs) = ponto x + pontos xs
where
ponto (x,y) = x + y
7. Escreva a funo garagem que associe uma lista de "pedras" ao maior
mltiplo de 5 (cinco), menor ou igual soma dos pontos nela contidos.
8. Escreva a funo pedra_igual_p que associe dois pares de inteiros a True
sss representam a mesma pedra e False caso contrrio. bom lembrar
que a ordem das pontas irrelevante, assim (2,4) e (4,2) representam a
mesma pedra.

1
63
9. Escreva a funo ocorre_pedra_p que associe uma "pedra" e uma "mo" a
True sss a "pedra" ocorre na "mo" e False caso contrrio.
10. Escreva a funo ocorre_valor_p que associe um valor vlido para "ponta"
e uma "mo" e produza True sss o valor ocorre em alguma pedra da mo e
False caso contrrio.
11. Escreva a funo ocorre_pedra que associe a um valor e uma "mo", uma
lista contendo as pedras da "mo" que possuem o valor dado.
12. Escreva a funo pedra_maior que associe uma "mo" a pedra de maior
valor na "mo" dada. Uma pedra p1 maior que uma outra p2 sss a soma
das pontas de p1 for maior que a soma das pontas de p2.
13. Escreva a funo ocorre_valor_q que associe um valor e uma "mo" e
produza o nmero de pedras na mo que possuem o valor dado.
14. Escreva a funo ocorre_carroca_q queassocie uma mo quantidade de
carroas nela existentes.
15. Escreva a funo tira_maior que associe uma mo a uma lista similar
"mo" de onde foi extrada a pedra de maior ponto.
16. Escreva a funo tira_maior_v que associe um valor e uma "mo" lista
similar "mo" de onde se extraiu a pedra de maior pontos de um
determinado valor para ponta.
Grupo III
O jogo se desenvolve pela colocao, pelo Jogador da vez, de uma pedra que
combine com alguma das "pontas" da "mesa". Num momento genrico do jogo
temos quatro pontas disponveis para execuo de uma jogada. Uma ponta pode
ser simples ou uma carroa. As carroas so dispostas de tal forma que todos os
seus pontos estejam para "fora".
Chamaremos "mesa" lista de pontas disponveis para jogada. Pontas simples
sero representadas por listas de um elemento e carroas por uma lista com dois
elementos idnticos. Por exemplo, a "mesa" ilustrada na Figura 18.2
representada pela qudrupla ( [5,5], [5], [0],[4] ).
Uma ponta ainda no aberta representada por lista vazia. Dizemos que h
marcao de pontos em uma mesa quando a soma das pontas um mltiplo de 5.
Os pontos a serem marcados a soma das pontas, com as carroas contando em

1
64
dobro.

Figura 18.2 desenvolvimento do jogo, no instante em que temos nas


pontas externas, uma carroa de quina, uma quina, branco e quadra.

17. Escreva a funo mesap que associe uma qudrupla de listas a True sss a
qudrupla for uma descrio vlida de "mesa".
Soluo:
mesap (p1,p2,p3,p4) = vponta p1 && vponta p2 &&
vponta p3 && vponta p4
where
vponta (x:y:xs) = if not (null xs)
then False
else validap x && vponta (y:xs)
vponta (x :[ ] ) = validap x
validap x
= elem x [0..6]

18. Escreva a funo carroca_m_p que associe uma mesa a True sss pelo
menos uma das pontas for carroa.
19. Escreva a funo pontos_marcados que associe uma mesa ao o nmero
de pontos a serem marcados se a soma das pontas for mltiplo de cinco e
zero em caso contrrio.

1
65
20. Escreva a funo pode_jogas_p que associe uma "pedra" e uma "mesa" a
True sss a pedra possui uma ponta que combina com pelo menos uma das
pontas da mesa.
21. Escreva a funo marca_ponto_p que tenha como entrada uma "pedra" e
uma "mesa" e produza True sss a pedra pode ser jogada fazendo pontos
em uma das pontas da mesa. Lembre-se que as carroas devem ser
contadas pelas duas pontas da pedra.
22. Escreva a funo maior_ponto que tenha associa uma pedra e uma mesa
ao nmero da "ponta" da mesa onde pode ser marcado o maior valor de
ponto que ser marcado pela pedra. Considere que a em uma "mesa" as
pontas so numeradas a partir de zero, da esquerda para a direita.
23. Escreva a funo joga_pedra que associe uma "pedra", uma "mesa" e um
nmero de "ponta" da mesa a uma nova mesa obtida ao se jogar a "pedra"
na "ponta" indicada.
24. Escreva a funo jogap que associe uma "mo" e uma "mesa" e produza
True sss existe pelo menos uma pedra na mo que possa ser jogada em
pelo menos uma ponta da mesa. Caso contrrio produza False.
25. Escreva a funo jogada que associe uma "mo" e uma mesa ao nmero
da pedra na mo e nmero da ponta na mesa onde pode ser feita a jogada
que marque mais ponto. Considere inclusive jogada onde no h marcao
de ponto.
26. Escreva a funo faz_jogada que associe uma "mo" e uma "mesa" e
produza uma nova "mesa" obtida por se jogar marcando o maior nmero de
pontos possvel
19.2 Banco de Sangue: para facilitar o atendimento da demanda por transfuses
de sangue o sistema de sade criou os chamados Bancos de Sangue. Como
sabemos, cada transfuso s pode ser realizada usando tipos de sangue
apropriados. A adequao de um determinado tipo de sangue baseada em
estudos cientficos que identificou quatro tipos sangneos, denominados de A, B,
AB e O. Outros estudos identificaram ainda a existncia do chamado fator RH que
pode ser positivo (+) ou negativo (-), assim o sangue de qualquer indivduo
classificado de acordo com esses dois atributos. Por exemplo, dizemos que fulano
possui sangue tipo O e fator RH positivo, e abreviamos para O+. Em um dado
Banco de Sangue, diariamente, so feitas doaes por pessoas de diferentes tipos
sangneos, para as quais feito um registro contendo o nmero da carteira de
identidade do doador (RG), o sexo (S), a data da doao (DD), a data de
nascimento (DN), o tipo sangneo (TS), o fator RH (RH) e a quantidade doada
(QD) (250 ou 500 ml). O sangue doado guardado em recipientes com uma
capacidade fixa (250 ml). Tambm, diariamente so feitas requisies pelos
hospitais (H), cada requisio indica as caractersticas do sangue (tipo e fator RH)
e a quantidade solicitada (QS). Sabemos que homens e mulheres possuem
intervalos de tempo diferentes para fazer doaes. Para homens o intervalo
mnimo de 2 (dois) meses e para mulheres de 3 (trs). A idade mxima para
doadores 60 anos.

1
66
Sejam as seguintes estruturas
Doao
Requisio

(RG, S, DD, DN, TS, RH, QD)


(H, TS, RH, QS)

Exerccios: Escreva programas em HUGS para resolver os seguintes problemas:


1. Dada uma lista de doaes, obtenha a quantidade total de sangue doado por
tipo sangneo e fator RH. O resultado ser uma tupla (um item para cada
combinao de tipo sangneo com fator RH) com triplas explicitando o tipo
sangneo, o fator RH e a quantidade total. Quando no houver doao de
uma dado par tipo-fator deve ser indicado o valor zero. Por exemplo:
( (A, +, 0), ... (O,+, 5500) ...)
2. Para uma dada lista de doaes, determine a lista dos dias de um dado ms
onde as doaes foram menores que a mdia mensal.
3. Dada uma lista de doaes e a data atual, determine a lista de doadores que j
esto aptos a fazerem novas doaes.
4. Dada a lista de doadores e o ms, determinar o nmero de doadores que esto
aptos a doar sangue naquele ms. (Essa e a questo 3 parecem anlogas,
no?)
5. Determine a relao de doadores que fazem doaes com o maior ndice de
regularidade. O ndice de regularidade dado pela nmero de vezes que o
intervalo entre as doaes coincidem, dividido pelo nmero de doaes menos
um.
6. Dada a lista de doadores, verificar o tipo sangneo que mais comumente
doado.
7. Dada a lista de doadores e o ano, determine o ms em que houve mais
doaes naquele ano.
8. Dada a lista de requisies de um determinado hospital, determinar a lista de
tipos sangneos com os respectivos fatores RH, que possuem seus pedidos
atendidos pelo banco de sangue.
9. Determinar, para um dado hospital em um determinado ano, a demanda
mensal de sangue, por tipo sangneo e fator RH.
10. Determinar a lista de doadores que no esto mais aptos a fazer doaes,
considerando a data atual.
11. Considere o estoque atual do banco de sangue, determinado pela funo
estoque (prob 1), e uma lista com vrias requisies. Leve em conta que o

1
67
estoque pode ser insuficiente para atender completamente todos os pedidos.
Determine o estoque atualizado aps o atendimento dos pedidos e produza
uma lista das requisies atendidas, constando a quantidade que foi de fato
fornecida.
12. No problema 11, considere que voc deseja atender cada hospital solicitante,
de forma proporcional ao seu pedido, considerando os pedidos de cada tipo
sangneo separadamente. Por exemplo, suponha que: o total de pedidos de
sangue O+ de 12.000 ml, que o hospital h1 solicitou 3.000 ml de sangue
O+ e que no estoque 8.000 ml. Podemos observar que o pedido para o sangue
O+ do hospital h1 representa 25 % do total. Neste caso o hospital h1 ser
atendido com 25 % de 8.000 ml que representa 2.000 ml. Produza uma lista
como os pedidos atendidos e outra com os pedidos pendentes.
13. Considere a poltica de atendimento do problema 12 mas leve em conta que
um dado pedido deve ser atendido completamente. Considere o exemplo do
problema anterior, e suponha que os pedidos do hospital h1 para o sangue
O+ so 4, (h1, O, +, 1.500), (h1, O, +, 1.000) e (h1, O, +, 250) e (h1, O,
+, 500). Neste caso, considerando que os pedidos esto em ordem de
prioridade, seriam atendidos os pedidos (h1, O, +, 1.500) e (h1, O, +, 250).
14. Modifique a poltica de atendimento do problema 14 para que o atendimento
seja tal que o hospital h1 use da melhor forma possvel a proporcionalidade
que lhe cabe. No caso do exemplo apresentado no problema 14, o pedido de
250 ml seria descartado visto que atendendo o pedido de 500 ml o hospital h1
estar usando melhor a parte que lhe cabe. (escolher a combinao mais
apropriada)

19.3 Correio Eletrnico: Considere um sistema de mensagens eletrnicas. Uma


mensagem pode ser descrita por uma tupla contendo o remetente, o destinatrio,
a data de envio, o assunto e o corpo da mensagem. Mensagens podem ser
acumuladas em listas para posterior acesso. Para facilitar o acesso podemos
construir ndices baseados nos dados contidos na mensagem. Por exemplo,
podemos ter um ndice baseado no remetente para facilitar o acesso a todas as
mensagens de um dado remetente. Considere as seguintes estruturas:
mensagem
ndice

(remetente, destinatrio, data, assunto, corpo)


[ (argumento1,[ordem na lista de mensagens]), (argumento2, []), ...]

Exerccios: Elabore programas em HUGS, usando recurso, para atender aos


seguintes problemas. A interface (nome e parmetros) das funes dado em
cada uma das questes.
1. (indexa msgs) Dada uma lista de mensagens, produza o ndice das
mensagens por remetente. Um ndice ter a seguinte estrutura: [ (remetente1,
lista de ocorrncias), (remetente2, lista de ocorrncias), ...] onde lista de

1
68
ocorrncias formada pela posio na lista de mensagens onde o remetente
ocorre.
Por exemplo:
[ (jose@inf.ufes.br, [1, 23]), (maria@inf.ufes.br, [10, 20, 50]), ...]
2. (consulta r p) Considere definidos um ndice por remetente, um ndice por
palavras constantes no assunto das mensagens e uma lista de mensagens.
Dados um remetente (r) e uma palavra(p), obtenha a lista de mensagens
enviadas por r onde a palavra p ocorre no assunto.
remetentes
palav_assunto
mensagens

= [(remetente1, [...]),(remetente2, [...]), ... ]


= [ (palavra1. [...]),(palavra2. [...]), ... ]
= [ mensagem1, mensagem2, mensagem3, ... ]

3. (msgPmes a r msgs) Dado um ano (a), um remetente (r) e uma lista de


mensagens (msgs), verificar a quantidade mensagens enviadas por r em cada
ms.
4. (busca p ind msgs) Considere um ndice construdo na forma de lista (indb). O
primeiro elemento um par com uma palavra (p) e a lista de mensagens
(msgs) onde p ocorre, o segundo elemento uma lista no mesmo formato de
indb, para as palavras menores que p e o terceiro para as palavras maiores
que p.
ndice = [ (palavra1, [...]), ndice para palavras menores que p, ndice para
palavras maiores que p]
Quando no houver palavras menores ou maiores que uma dada palavra, o
ndice igual a uma lista vazia.
Dada uma palavra p, o ndice (indb) e a lista de mensagens (msgs), descreva
a lista mensagens onde p ocorre, usando o ndice dado.

5.

(palavPassunto msgs) Considere definida uma lista de palavras irrelevantes


(lis). Dada uma lista de mensagens (msgs) produza um ndice com as palavras
distintas que ocorrem nos assuntos das mensagens e no ocorrem em lis.
Para cada palavra deve ser produzido tambm a lista das posies na lista de
mensagens (msgs) onde ela ocorre.
lis

= [ palavra1, palavra2. ... ]

6. (releva msgs li lf) Dada uma lista de mensagens podemos obter uma lista de
palavras relevantes. Define-se como palavra relevante em uma lista
mensagens (msgs) aquelas cuja freqncia satisfazem um intervalo para o
qual so dados um limite superior (ls) e um limite inferior (li).

1
69

7.

(constante msgs a) Dada uma lista de mensagens (msgs), determinar a lista


de remetentes que enviaram pelo menos uma mensagem para cada ms de
um dado ano a.

8.

(freqData msgs m) Para uma dada lista de mensagens desejamos obter a


quantidade de mensagens para cada dia de um dado ms m.

9. (identico indb1 indb2) Dados dois ndices no formato de rvore binria de


pesquisa desejamos verificar se so idnticos. Dizemos que dois ndices so
idnticos quando a palavras e as listas de ocorrncia coincidem e os
subndices das palavras menores e o das palavras maiores respectivamente
so idnticos.
ndice = ( (palavra1, [...]),
ndice para palavras menores que p, ndice para palavras maiores que p)
10. (palavOrd indb) Dado um ndice no formato de rvore binria de pesquisa
produza uma lista das palavras nele contidas de tal forma que as palavras se
apresentem em ordem alfabtica crescente.
11. (resgate indb) Dado um ndice no formato de rvore binria de pesquisa
produza uma lista das palavras que ocorrem em cada mensagem. A lista
resultante ter o seguinte formato:
[ [palavras da mensagem de ordem 0], [palavras da mensagem de ordem 1 ], ... ]

12. (balance arbinpq) Uma rvore binria de pesquisa est balanceada se e


somente se a quantidade (q1) de elementos no subindice das palavras
menores difere da quantidade (q2) de elementos no subindice das palavras
maiores de no mximo um (1) e q1 maior ou igual a q2.
q2 + 1 >= q1 >= q2

13. (insOrd indb msg) Dados um ndice (indb) no formato de rvore binria de
pesquisa e uma mensagem (msg), descreva a nova rvore obtida pela
insero das palavras das mensagem (msg), exceto as irrelevantes.

14. (perfil msg diret fga) Um diretrio uma lista de assuntos, cada um dos
quais associado a uma coleo de palavras. Dada uma mensagem e um
diretrio podemos atribuir mensagem um perfil que uma lista de valores
indicando o grau de aproximao (ga) dela com cada assunto. O ga de uma
mensagem com respeito a um assunto pode ser obtido com base na
freqncia com que as palavras a ele associadas ocorrem na mensagem.

1
70
Considere que a funo que calcula o ga fornecida e opera sobre uma lista
de inteiros.
Considere os seguintes formatos:
Diretrio
Perfil

[ (assunto1, [palavra1, palavra2, ...]), (assunto2, [palavra1, palavra2, ...]), ...]


[ (assunto1, ga1), (assunto2,ga2), ...]

19.4 Lista de Compras: Para realizar um determinado projeto necessitamos


adquirir certos componentes eletrnicos. No mercado de componentes existem
vrios fornecedores que vendem seus produtos com preos diferenciados. A
escolha da melhor alternativa para satisfao de nossas compras depende de
vrios fatores, dos quais o melhor preo um dos mais importantes.
Considere as seguintes definies:
Tabela
Preo

de Uma lista contendo todos os preos dos componentes comercializados por um


determinado revendedor. Cada elemento da lista um par no formato
(material, preo).
Exemplo:
[(potenciometro, 2.50), (resistor-100k, 0.30), (capacitor-10mF,0.50), (indutor10R,3.00)]
Pedido
de Uma lista contendo todos os materiais necessrios para um determinado projeto,
Compra
com suas respectivas quantidades. Cada elemento da lista um par no formato
(material, quantidade).
Exemplo: [(transformador, 50), (fonte DC, 10), (resistor-200k,100)]
Lista
de Uma lista contendo a tabela de preos de todos os revendedores, no formato:
Revendedores
[ (revendedor1, [tabela de preo] ), ...]

Exerccios: Elabore programas em HUGS, usando recurso, para


atender aos seguintes problemas. O nome das funes dado em cada
uma das questes.
1. (custo) Dado o resultado da pesquisa de preos de um pedido de compra,
para um certo fornecedor, no formato [ (material1, qtde, preo), (material2,
qtde, preo), ... ], queremos obter o custo total da compra se optarmos por
esse fornecedor.
2. (fornece) Dado um pedido de compra e a tabela de preos de um determinado
revendedor, obtenha a lista dos materiais que ele pode fornecer.
3. (subprojeto) Considere os pedidos de compra para dois projetos (p1 e p2).
Eventualmente alguns itens do pedido do projeto p1 podem ocorrer no pedido
de p2, possivelmente com quantidades distintas. Dizemos que um projeto p1
subprojeto de p2 se cada componente de p1 tambm componente de p2 em
quantidade idntica ou inferior.
4. (lfornecedor) Dado um pedido de compra e a lista de revendedores, descrever
a lista de fornecedores para cada componente, com seus respectivos preos,
no formato
[(material1,[rev1, rev2,...] ), (material2, [...]), ...]

1
71
19.5 Passagens areas: Considere que vrias companhias areas brasileiras
oferecem vos dirios para vrias regies do mundo. Devido a competitividade do
mercado, vrias so as ofertas promocionais de vos nacionais e internacionais.
Cada vo identificado pela companhia area, o nmero do vo, a rota, a tarifa
em reais e a data de partida. A rota descrita por uma lista onde o primeiro
elemento corresponde origem, o ltimo elemento corresponde ao destino e os
outros elementos correspondem s escalas do vo. Para escolher e reservar um
determinado vo, um passageiro deve fornecer as seguintes informaes: a
origem, o destino e a data de partida desejados. Um vo atende a um pedido de
reserva se, para a data de partida desejada, a origem requisitada coincide com a
origem definida na rota do vo e o destino requisitado coincide com alguma escala
ou com o destino da rota do vo. A tarifa a mesma, da origem para qualquer
escala ou destino da rota. Considere as seguintes definies:
vo

Consiste em uma tupla definida com os seguintes componentes:


(<companhia area>, <no>, <rota>, <tarifa>, <partida>)
Exemplo:
(VARIG,480,[rio,salvador,macei],430,(09,07,2001))

Pedido de Uma tupla definida com os seguintes componentes:


reserva
(<origem>, <destino>, <partida>)
Exemplo: (rio, salvador, (09,07,2001))
Obs:
Companhia area, origem e destino so do tipo string, rota uma lista
de strings, n e tarifa so nmeros e partida uma tripla de nmeros.
Exerccios: Elabore programas em HUGS para resolver os problemas propostos.
O nome das funes assim como seus parmetros so dados para cada uma das
questes. Escolha duas questes para resolver utilizando descrio por listas e
duas utilizando recurso.
1. (vos lv pr) Dada uma lista de vos e um pedido de reserva, descreva a lista
de companhias areas que atendem ao pedido de reserva.
2. (mtarifa lv pr) Considerando a funo descrita na questo anterior, das
companhias areas que atendem a um determinado pedido de reserva, obter
aquela que oferece a menor tarifa.
3. (partidas dt ds lv) Dados uma data e um destino, obter o nmero de partidas
para aquele destino, naquela data.
4. (vsescalas lv dt) Dada a lista de vos, descrever a lista de vos sem escalas,
atravs do nmero do vo. A resposta deve ser no formato:
[ n do vo,...]

1
72
19.6 Gerncia Acadmica: Considere a gerncia acadmica dos cursos de
graduao de uma universidade. As disciplinas cursadas por um aluno so
registradas em seu histrico. O registro deve conter o cdigo da disciplina, o ano e
o semestre em que foi cursada e a nota obtida. Semestralmente o aluno deve
requerer matrcula em novas disciplinas. O pedido de matrcula realizado atravs
da apresentao das disciplinas desejadas pelo aluno. Um dos critrios para
conseguir se matricular em uma disciplina que o aluno tenha cumprido, com
aprovao, os pr-requisitos da disciplina. Um aluno aprovado em uma disciplina
se obtiver mdia superior ou igual a 5 (cinco). Cada curso possui uma grade
curricular que relaciona cada disciplina do curso com seus respectivos prrequisitos.
Considere as seguintes definies:
Histrico Escolar

Um par contendo o cdigo de matrcula do aluno e a lista de


disciplinas cursadas. Cada disciplina cursada representada por
uma tripla com o cdigo da disciplina, o ano e o semestre que ela
foi cursada e a nota obtida.
Formato: (matrcula, [ (disciplina, (ano, semestre), nota), ... ]) onde
matrcula = (ano, curso, nmeroIdentificaoIndividual)
Cadastro de
Uma lista contendo, para cada disciplina, um par com o cdigo da
Disciplinas
disciplina e a quantidade de crditos.
Grade Curricular
Um par com o cdigo do curso e uma lista de pares onde cada par
representa uma disciplina (cdigo) e uma lista dos seus prrequisitos.
Formato: (curso, [(disciplina, [disciplina, disciplina,...]), ...])
Pedido de matrculaUm par com o cdigo do aluno e uma lista contendo o cdigo das
disciplinas nas quais o aluno deseja se matricular.
Formato: (matrcula, [pedido1, pedido2, ...])
Oferta
Uma lista contendo as turmas a serem ofertadas, com seus horrios
e limite de vagas.
Formato: [(disciplina, turma, quantidade_de_vagas, horrio),...]
onde
horrio = [(dia_da semana, hora_inicial, hora_final), ...]
Lista de disciplinas Um par contendo o cdigo do curso e uma lista de pares, onde cada
de um curso,
par representa um perodo do curso e uma lista das disciplinas do
apresentadas por perodo.
perodo
Formato: (curso, [(perodo, [disciplina, disciplina,...])

Histrico
Escolar

Cadastro de
Disciplinas
Grade
Curricular

Um par contendo o cdigo de matrcula do aluno e a lista de


disciplinas cursadas. Cada disciplina cursada representada
por uma tripla com o cdigo da disciplina, o ano e o semestre
que ela foi cursada e a nota obtida.
Formato: (matrcula, [ (disciplina, (ano, semestre), nota), ... ])
onde
matrcula = (ano, curso, registro)
Uma lista contendo, para cada disciplina, um par com o cdigo
da disciplina e a quantidade de crditos.
Um par com o cdigo do curso e uma lista de pares onde cada
par representa uma disciplina (cdigo) e uma lista dos seus pr-

Lista de
disciplinas de
um curso,
apresentadas
por perodo

73
requisitos.
Formato: (curso, [(disciplina, [disciplina, disciplina,...]), ...])
Um par contendo o cdigo do curso e uma lista de pares, onde
cada par representa um perodo do curso e uma lista das
disciplinas do perodo.
Formato: (curso, [(perodo, [disciplina, disciplina,...])

Exerccios: Escreva funes em Hugs para resolver os problemas propostos


abaixo, usando os nomes indicados em negrito. A palavra semestre, nestes
problemas, representa um elemento do tipo (ano,s), onde s = 1 ou s = 2.
1.

(credse) Dado um histrico, o cadastro de disciplinas e um semestre,


descrever o total de crditos cumpridos no semestre.

2.

(ncred) Dado um histrico e o cadastro de disciplinas, descrever a quantidade


de crditos cumpridos por semestre.

3.

(dncursadas) Dado um histrico e uma lista com as disciplinas por perodo,


descrever a lista das disciplinas no cursadas ainda pelo aluno, dos perodos
j cumpridos. Esta lista deve ter o seguinte formato: [(perodo,[disciplina,..]),
(perodo,[disciplina,...]),...]

4.

(maxcred) Dada uma lista de histricos, identificar a lista de alunos que


possuem o maior nmero de crditos cumpridos.

5.

(conterep) Dado um histrico, contar o nmero de reprovaes.

6.

(jubila) Verificar se um determinado aluno se encontra em situao de


jubilamento (possui trs reprovaes em uma mesma disciplina).

7.

(abandono) Verificar se o aluno deixou de cursar disciplinas em algum


semestre.

8.

(divida) Obter a lista das disciplinas que foram cursadas por um dado aluno,
nas quais ele ainda no obteve aprovao.

9.

(reprova) Obter uma lista de reprovaes por perodo, para um dado aluno.
(crend) O coeficiente de rendimento (CR) de um dado aluno
determinado pela mdia ponderada das notas obtidas, tendo como peso, o
nmero de crditos das disciplinas. Determine o CR de um dado aluno.

10.

(semprereq) Obter uma lista das disciplinas de um dado curso, que no


possuem pr-requisito.

11.

(cumprereq) Dada uma disciplina, verificar se o aluno cumpriu seus


pr-requisitos.

12.

(dividas) Obter para um dado aluno, a lista de disciplinas que ele ainda
no cursou, com respeito a uma dada grade curricular.

13.

(sugestao) Obter para um dado aluno, a lista de disciplinas que ele est
apto a cursar, com respeito a uma dada grade curricular.

14.

1
74
(lcumprereq) Obter uma lista de pedidos de disciplinas para as quais os
pr-requisitos foram cumpridos.

15.

(ldiscsol) Dada uma lista com os pedidos de todos os alunos, obtenha


uma lista das disciplinas solicitadas, sem repetio.

16.

(sol_disciplinas_ord) Obter a lista de alunos que solicitaram uma dada


disciplina, com seus respectivos coeficientes de rendimentos. A lista de alunos
deve estar em ordem crescente por coeficiente de rendimento. A lista
resultante deve ter o seguinte formato:

17.

[(aluno1, coeficiente_de_rendimento1),(aluno2, coeficiente_de_rendimento2), ...]

19.7 Agncia de Turismo: Uma agncia de turismo possui o mapa atualizado de


reservas dos hotis de uma determinada regio. Para cada hotel, todas as
informaes pertinentes aos tipos de quarto oferecidos so registrados no mapa.
Este mapa representado por uma lista de tuplas, seguindo o seguinte formato:
[(nome_hotel, [(tipo_quarto, valor_diria, situao), ...] ), ...] onde

nome_hotel do tipo string;


tipo_quarto uma string;
valor_diria um nmero real positivo;
situao: nmero inteiro positivo que indica a quantidade de quartos
livres do tipo indicado.

Para o melhor entendimento da representao da lista de hotis no hugs,


considere o seguinte exemplo:
lhoteis = [("peterle", [("simples", 50.0, 5),("duplo", 75.8, 10), ("luxo", 110.0, 2)] ),
("ibis", [("simples", 45.0, 3),("duplo", 65.5, 15), ("luxo", 95.0, 3)] ),
("novotel", [("simples", 65.6, 10),("duplo", 90.5, 20), ("luxo", 150.0, 10)] )]
Exerccios: Considerando o formato desta lista de hotis apresentada acima,
resolva o seguinte problema, descrevendo funes em HUGS.
1. Dados um tipo de quarto e a lista de hotis, apresente a lista com o nome do
hotel ou com os nomes dos hotis que possuem a oferta mais barata para
aquele tipo de quarto.
2. Avalie a funo definida no problema 1 para os parmetros adequados,
considerando a lista de hotis como a dada acima.
19.8 Espetculos Teatrais: Vrios espetculos esto sendo apresentados em um
grande teatro da cidade. Para cada um dos espetculos, registra-se o mapa de

1
75
ocupao da platia, conforme as vendas dos ingressos. A platia est
representada por m filas numeradas de 1 a m, sendo que cada fila contm n
cadeiras tambm numeradas de 1 a n. Considere a seguinte representao para
os dados:
Lugar na platia (fila, cadeira), onde fila representada por um inteiro de 1 a m e
cadeira, por um inteiro de 1 a n.
Platia
Lista de duplas (lugar, situao) sendo que a situao : 1 para
indicar lugar ocupado e 0 para indicar lugar vago.
Lista de duplas (espetculo, platia) onde espetculo representado
Teatro
por um inteiro de 1 a p.
Exerccios: Escreva um script em HUGS, com funes que resolvam os
problemas abaixo. Nomes para cada uma das funes so sugeridos ao final do
enunciado de cada problema.
5. Dada uma platia pls, descreva a quantidade total de lugares ocupados
(totalOcup).
6. Dado um lugar lg e uma platia pls, verifique se o lugar lg est livre (estaLivre).
7. Dado um lugar lg e uma platia pls, verifique se existe algum vizinho lateral de
lg que est livre (vizinhoLivre).
8. Dada uma fila fl e uma platia pls, descreva a lista de cadeiras livres da fila fl
(cadeirasLivresFila).
9. Dada uma platia pls, descreva a lista de cadeiras livres para cada fila
(lugLivresFila)
10. Dada uma platia pls, descreva a(s) lista(s) com o maior nmero de cadeiras
livres (filaMaxLivre).
11. Dado um teatro trs e um espetculo ep, descreva a sua platia (plateiaEsp).
12. Dado um teatro trs, um espetculo ep e uma fila fl, descreva a lista de cadeiras
livres da fila fl (cadeirasLivresFilaEsp).

1
76
20. ENTRADA E SAIDA DE DADOS
20.1 INTRODUO:
Os programas que apresentamos e propusemos at ento, se basearam em um
padro especfico de interao entre o usurio e o sistema. O interpretador HUGS
est constantemente solicitando uma expresso, que em seguida avaliada por
ele e o resultado apresentado ao usurio. Vejamos o modelo ilustrado na figura
20.1. A avalio de uma expresso leva em conta as definies disponveis em
bibliotecas e as construdas pelos programadores.

expresso

scripts

usurio

Interpretado
r HUGS

resultado

Figura 20.1 Modelo de Interao usurio-interpretador HUGS


Algumas vezes entretanto este modelo de interao no adequado tendo
em vista que o programa do usurio no pode tomar a deciso de pedir ou no um
dado ao usurio. Tudo tem que ser informado antecipadamente.
Exemplo 1: Desejamos fazer um programa que interaja com o usurio para
que ele tente descobrir um nmero oculto. A interao do programa s deve
continuar enquanto o jogador no descobrir o nmero oculto. E veja, no d para
antecipar antes e codificar isto em uma expresso. A Figura 20.2 mostra um
esquema da interao necessria. O programa pode comear pedindo um valor
ao usurio. Se o usurio fornece um valor idntico ao valor oculto, o programa
exibe a mensagem anunciando que o jogador venceu e encerra o jogo. Caso
contrrio o programa solicita um novo palpite.

1
77

Jogo encerrado

sim

valor

Valor fornecido
=
Nmero oculto
?

no
Fornea outro valor

Figura 20.2 Interaes para descobrir um nmero


oculto

Nestes casos, no queremos descrever mapeamentos entre conjunto de


valores e sim seqncia de aes. o contato das funes com o mundo. Ainda
podemos usar funes para determinar valores, mas quando precisamos, temos
que estabelecer uma seqncia de aes a serem executadas. Agora o que nos
interessa definir programas, atravs de seqncias de aes.
Vejamos uma soluo para o joguinho acima introduzido:

1
78
jogo1 = do
putStrLn ">>fornea um nmero entre 0 e 10"
valor <- getLine
if valor == "5"
then do putStrLn "acertou - parabns!"
else do putStrLn "errou - tente outra vez!"
jogo1

1
79
E algumas interaes:
Main> jogo1
>>fornea um nmero
3
errou - tente outra
>>fornea um nmero
4
errou - tente outra
>>fornea um nmero
2
errou - tente outra
>>fornea um nmero
5
acertou - parabns!

entre 0 e 10
vez!
entre 0 e 10
vez!
entre 0 e 10
vez!
entre 0 e 10

Vamos agora dissecar o programa:


1. Para estabelecer contato com o mundo precisamos de uma ao para
leitura e outra para exibio de resultado. Aqui a leitura realizada
atravs da primitiva getLine. Para exibir resultados fazemos uso da
primitiva putStrLn. Enquanto getLine no precisa de um parmetro,
visto que uma ao que sempre buscar na interao obter um valor, a
putStr necessita de um valor para ser exibido;
2. O programa jogo1 no precisa de parmetro para realizar sua atividade,
dado que tudo ser solicitado diretamente dentro do corpo do programa,
na medida do necessrio;
3. Para informar que o que estamos definindo uma seqncia de aes e
no uma descrio funcional, introduzida a partcula do, que pode ser
traduzida pelo imperativo faa!
4. Para que um valor obtido pelo comando de leitura getLine, se torne
disponvel para uso do programa precisamos internaliz-lo atravs do uso
da primitiva representada pelo smbolo ;

valor getLine
5. Para indicar que desejamos continuar executando o programa podemos
fazer uma chamada a ele mesmo, como o fizemos em:
else do putStrLn "errou - tente outra vez!"
jogo1

1
80

Вам также может понравиться