You are on page 1of 198

INTRODUO PROGRAMAO

PROLOG
Luiz A. M. Palazzo
Editora da Universidade Catlica de Pelotas / UCPEL
Rua Flix da Cunha, 412 - Fone (0532)22-1555 - Fax (0532)25-3105
Pelotas - RS - Brasil
EDUCAT
Editora da Universidade Catlica de Pelotas
Pelotas, 1997

1997 LUIZ A. M. PALAZZO


SUMRIO
1. LGICA E PROGRAMAO DE COMPUTADORES 1
1.1 AS RAZES 1
1.2 PROGRAMAO EM LGICA 2
1.3 APLICAES 4
1.4 A QUINTA GERAO 6
1.5 PORQUE ESTUDAR PROLOG 8
RESUMO 9
2. A LINGUAGEM PROLOG 11
2.1 FATOS 11
2.2 REGRAS 14
2.3 CONSTRUES RECURSIVAS 17
2.4 CONSULTAS 19
2.5 O SIGNIFICADO DOS PROGRAMAS PROLOG 21
RESUMO 22
EXERCCIOS 22
3. SINTAXE E SEMNTICA 24
3.1 OBJETOS 24
3.2 UNIFICAO 27
3.3 SEMNTICA DECLARATIVA E SEMNTICA PROCEDIMENTAL 28
3.4 SEMNTICA OPERACIONAL 30
RESUMO 30
EXERCCIOS 31
4. OPERADORES E ARITMTICA 33
4.1 OPERADORES 33
4.2 ARITMTICA 36
RESUMO 38
EXERCCIOS 39
5. PROCESSAMENTO DE LISTAS 41
5.1 REPRESENTAO DE LISTAS 41
5.2 OPERAES SOBRE LISTAS 42
5.3 OUTROS EXEMPLOS 48
RESUMO 49
EXERCCIOS 50
6. CONTROLE 51
6.1 BACKTRACKING 51
6.2 O OPERADOR "CUT" 52
6.3 APLICAES DO CUT 56
6.4 NEGAO POR FALHA 57
6.5 CUIDADOS COM O CUT E A NEGAO 58
RESUMO 60
EXERCCIOS 60
7. ESTRUTURAS DE DADOS 62
7.1 RECUPERAO DE INFORMAES 62
7.2 ABSTRAO DE DADOS 64
7.3 UM AUTMATO FINITO NO-DETERMINSTICO 65
7.4 PLANEJAMENTO DE ROTEIROS AREOS 67
RESUMO 69
EXERCCIOS 69
8. ENTRADA E SADA 71
8.1 ARQUIVOS DE DADOS 71
8.2 PROCESSAMENTO DE ARQUIVOS DE TERMOS 73
8.3 PROCESSAMENTO DE CARACTERES 77
8.4 CONVERSO DE TERMOS 78
8.5 LEITURA DE PROGRAMAS 79
RESUMO 80
EXERCCIOS 80
9. PREDICADOS EXTRALGICOS 82
9.1 TIPOS DE TERMOS 82
9.2 CONSTRUO E DECOMPOSIO DE TERMOS 84
9.3 EQUIVALNCIAS E DESIGUALDADES 85
9.4 PROGRAMAS OU BASES DE DADOS? 86
9.5 RECURSOS PARA O CONTROLE DE PROGRAMAS 89
9.6 BAGOF, SETOF E FINDALL 89
RESUMO 91
EXERCCIOS 91
10. LGICA E BASES DE DADOS 93
10.1 BASES DE DADOS RELACIONAIS 93
10.2 RECUPERAO DE INFORMAES 95
10.3 ATUALIZAO DA BASE DE DADOS 96
10.4 MODELAGEM DE DADOS 97
10.5 ALM DO MODELO RELACIONAL 99
10.6 REDES SEMNTICAS 99
RESUMO 103
EXERCCIOS 103
11. PROGRAMAO SIMBLICA 105
11.1 DIFERENCIAO SIMBLICA 105
11.2 MANIPULAO DE FRMULAS 105
11.3 OS OPERADORES REVISITADOS 105
11.4 AVALIAO DE FRMULAS 106
11.5 SIMPLIFICAO ALGBRICA 107
11.6 INTEGRAO 109
RESUMO 109
EXERCCIOS 110
12. METODOLOGIA DA PROGRAMAO EM LGICA 111
12.1 PRINCPIOS GERAIS DA BOA PROGRAMAO 111
12.2 COMO PENSAR EM PROLOG 112
12.3 ESTILO DE PROGRAMAO 114
12.4 DEPURAO DE PROGRAMAS 116
12.5 EFICINCIA 117
12.6 PROGRAMAO ITERATIVA 122
RESUMO 123
EXERCCIOS 124
13. OPERAES SOBRE ESTRUTURAS DE DADOS 125
13.1 CLASSIFICAO EM LISTAS 125
13.2 REPRESENTAO DE CONJUNTOS 127
13.3 DICIONRIOS BINRIOS 129
13.4 INSERO E REMOO DE ITENS EM DICIONRIOS BINRIOS 130
13.5 APRESENTAO DE RVORES 133
13.6 GRAFOS 133
RESUMO 138
EXERCCIOS 139
14. ESTRATGIAS PARA A SOLUO DE PROBLEMAS 140
14.1 CONCEITOS BSICOS 140
14.2 PESQUISA EM PROFUNDIDADE 143
14.3 PESQUISA EM AMPLITUDE 146
14.4 PESQUISA EM GRAFOS, OTIMIZAO E COMPLEXIDADE 150
RESUMO 151
EXERCCIOS 151
15. PESQUISA HEURSTICA 153
15.1 BEST-FIRST SEARCH 153
15.2 UMA APLICAO DA PESQUISA HEURSTICA 158
RESUMO 160
EXERCCIOS 161
16. REDUO DE PROBLEMAS E GRAFOS E/OU 162
16.1 REPRESENTAO DE PROBLEMAS 162
16.2 EXEMPLOS DE REPRESENTAO DE PROBLEMAS EM GRAFOS E/OU 165
16.3 PROCEDIMENTOS BSICOS DE PESQUISA EM GRAFOS E/OU 167
16.4 PESQUISA HEURSTICA EM GRAFOS E/OU 170
RESUMO 178
EXERCCIOS 178
APNDICE A 179
A.2 SEMNTICA MODELO-TEORTICA 182
A.3 SEMNTICA PROVA-TEORTICA 189
BIBLIOGRAFIA 191
Tanto pelo privilgio da amizade de vrios anos, como pela condio de colega profissional
do prof. Luiz Antonio Palazzo, j h muito acompanho sua contribuio cultura em Cincia
da Computao na regio em que trabalhamos (zona sul do Rio Grande do Sul). Com gradu-
ao e ps-graduao pela UFRGS, vem marcando sua atuao desde a poca de estudante,
tanto no meio acadmico como na comunidade em geral, por uma postura de vanguarda na
busca de tecnologias para um uso racional e eficiente da computao. Sem dvida, este livro
permitir que um nmero maior de pessoas se beneficiem de sua larga experincia no ofcio
de ensinar.
A estrutura do livro mescla o contexto histrico da Inteligncia Artificial (IA) com o estudo
do Prolog, uma das mais difundidas linguagens para Programao em Lgica. O contedo,
por sua vez, tem como ponto alto contemplar uma rigorosa conceituao formal, cujo empre-
go caracterizado por exemplos claros e significativos.
O emprego das linguagens para Programao em Lgica ganhou significativo impulso com o
projeto Japons de Sistemas Computacionais de Quinta Gerao (1982-1992), o qual investi-
gou alternativas de hardware e software para atender o desenvolvimento de aplicaes que
contemplavam metas ambiciosas, tais como reconhecimento de imagens, processamento da
linguagem natural, processamento de conhecimento, etc.
As linguagens para Programao em Lgica, a exemplo do Prolog, outrora empregadas
principalmente na prototipao, j podem ser utilizadas para resolver, com bom desempenho,
complexos problemas reais de IA. Isto se tornou possvel pela disponibilidade de processado-
res poderosos a custos reduzidos, bem como pela disseminao do uso de arquiteturas para-
lelas.
Neste trabalho so ressaltadas, com muita propriedade, as vantagens do emprego da lgica
clausal para programao de computadores, resgatando a "elegncia" das linguagens para
Programao em Lgica, nas quais o programador tem como principal preocupao a espe-
cificao em Prolog do problema a ser resolvido, ficando a cargo do sistema computacional
a gerncia dos mecanismos de busca das possveis solues.
Esta obra moderna, das poucas em portugus no seu estilo, vem preencher uma lacuna edito-
rial, trazendo a estudantes e profissionais da cincia da computao uma abordagem ampla,
porm no menos crtica e objetiva, das perspectivas do uso da Programao em Lgica.
Adenauer Corra Yamin
Pelotas, RS
1
1. LGICA E PROGRAMAO DE COMPUTADORES
A lgica a cincia do pensamento correto
1
. Esta declarao no implica contudo em afirmar que ela
seja a cincia da verdade. Mesmo que tudo o que se permita afirmar dentro da lgica seja suposta-
mente verdadeiro em determinado contexto, as mesmas afirmaes podem resultar falsas se aplicadas
ao mundo real. Os filsofos da lgica afirmam que, "para entender o que realmente acontece no mun-
do, precisamos entender o que no acontece", isto , as propriedades invariantes das entidades ou
objetos que o compem. Com essa idia em mente, podemos considerar lgicos os conjuntos de de-
claraes que possuem a propriedade de ser verdadeiros ou falsos independentemente do tempo ou
lugar que ocupam no universo considerado. Este insigth inicial costuma ser de grande valia para en-
tender como a lgica pode ser empregada na programao de computadores com grande vantagem
sobre as linguagens convencionais. O clculo proposicional, que o subconjunto da lgica matemti-
ca mais diretamente envolvido nesse processo, formaliza a estrutura lgica mais elementar do discurso
definindo precisamente o significado dos conetivos e, ou, no, se...ento e outros. No presente cap-
tulo esboa-se a forma como evoluiu a idia de empregar a lgica como linguagem de programao de
computadores, comenta-se os principais usos e aplicaes das linguagens baseadas na lgica, relata-se
os resultados mais significativos obtidos ao longo dos dez anos do controvertido projeto japons para
o desenvolvimento dos denominados "Computadores de Quinta Gerao" e, por fim, se tenta antecipar
as perspectivas mais promissoras da pesquisa neste ramo do conhecimento cientfico.
1.1 AS RAZES
O uso da lgica na representao dos processos de raciocnio remonta aos estudos de Boole (1815-
1864) e de De Morgan (1806-1871), sobre o que veio a ser mais tarde chamado "lgebra de Boole".
Como o prprio nome indica, esses trabalhos estavam mais prximos de outras teorias matemticas do
que propriamente da lgica. Deve-se ao matemtico alemo Gttlob Frege no seu "Begriffsschrift"
(1879) a primeira verso do que hoje denominamos clculo de predicados, proposto por ele como uma
ferramenta para formalizar princpios lgicos. Esse sistema oferecia uma notao rica e consistente
que Frege pretendia adequada para a representao de todos os conceitos matemticos e para a for-
malizao exata do raciocnio dedutivo sobre tais conceitos, o que, afinal, acabou acontecendo.
No final do sculo passado a matemtica havia atingido um estgio de desenvolvimento mais do que
propcio explorao do novo instrumento proposto por Frege. Os matemticos estavam abertos a
novas reas de pesquisa que demandavam profundo entendimento lgico assim como procedimentos
sistemticos de prova de teoremas mais poderosos e eficientes do que os at ento empregados. Al-
guns dos trabalhos mais significativos deste perodo foram a reconstruo axiomtica da geometria
abstrata por David Hilbert, a aritimtica proposta por Giuseppe Peano e a explorao intuitiva da teo-
ria geral dos conjuntos, por Georg Cantor, que tambm produziu a iluminada teoria dos nmeros
transfinitos. O relacionamento entre lgica e matemtica foi profundamente investigado por Alfred
North Whitehead e Bertrand Russel, que em "Principia Mathematica" (1910) demonstraram ser a l-
gica um instrumento adequado para a representao formal de grande parte da matemtica.
Um passo muito importante foi dado em 1930, em estudos simultneos, porm independentes, reali-
zados pelo alemo Kurt Gdel e o francs Jacques Herbrand. Ambos, em suas dissertaes de douto-
rado, demonstraram que o mecanismo de prova do clculo de predicados poderia oferecer uma prova
formal de toda proposio logicamente verdadeira. O resultado de maior impacto foi entretanto pro-
duzido por Gdel, em 1931, com a descoberta do "teorema da incompleteza dos sistemas de formali-
zao da aritmtica". A prova deste teorema se baseava nos denominados paradoxos de auto-
referncia (declaraes do tipo: "Esta sentena falsa", que no podem ser provadas nem verdadeiras

1
Na realidade, de uma certa classe de pensamento correto.
2
nem falsas). Em 1934, Alfred Tarski produziu a primeira teoria semntica rigorosamente formal do
clculo de predicados, introduzindo conceitos precisos para "satisfatibilidade", "verdade" (em uma
dada interpretao), "conseqncia lgica" e outras noes relacionadas. Ainda na dcada de 30, di-
versos outros estudos - entre os quais os de Alan Turing, Alonzo Church e outros - aproximaram
muito o clculo de predicados da forma com que hoje conhecido e estudado.
No incio da Segunda Guerra Mundial, em 1939, toda a fundamentao terica bsica da lgica com-
putacional estava pronta. Faltava apenas um meio prtico para realizar o imenso volume de computa-
es necessrias aos procedimentos de prova. Apenas exemplos muito simples podiam ser resolvidos
manualmente. O estado de guerra deslocou a maior parte dos recursos destinados pesquisa terica,
nos EUA, Europa e Japo para as tcnicas de assassinato em massa. Foi somente a partir da metade
dos anos 50 que o desenvolvimento da ento novssima tecnologia dos computadores conseguiu ofe-
recer aos pesquisadores o potencial computacional necessrio para a realizao de experincias mais
significativas com o clculo de predicados.
Em 1958, uma forma simplificada do clculo de predicados denominada forma clausal comeou a
despertar o interesse dos estudiosos do assunto. Tal forma empregava um tipo particular muito sim-
ples de sentena lgica denominada clusula. Uma clusula uma (possivelmente vazia) disjuno de
literais. Tambm por essa poca, Dag Prawitz (1960) props um novo tipo de operao sobre os ob-
jetos do clculo de predicados, que mais tarde veio a ser conhecida por unificao. A unificao se
revelou fundamental para o desenvolvimento de sistemas simblicos e de programao em lgica.
A programao em lgica em sistemas computacionais, entretanto, somente se tornou realmente pos-
svel a partir da pesquisa sobre prova automtica de teoremas, particularmente no desenvolvimento do
Princpio da Resoluo por J. A. Robinson (1965). Um dos primeiros trabalhos relacionando o Prin-
cpio da Resoluo com a programao de computadores deve-se a Cordell C. Green (1969) que mos-
trou como o mecanismo para a extrao de respostas em sistemas de resoluo poderia ser empregado
para sintetizar programas convencionais.
A expresso "programao em lgica" (logic programming, originalmente em ingls) devido a Ro-
bert Kowalski (1974) e designa o uso da lgica como linguagem de programao de computadores.
Kowalski identificou, em um particular procedimento de prova de teoremas, um procedimento com-
putacional, permitindo uma interpretao procedimental da lgica e estabelecendo as condies que
nos permitem entend-la como uma linguagem de programao de uso geral. Este foi um avano es-
sencial, necessrio para adaptar os conceitos relacionados com a prova de teoremas s tcnicas com-
putacionais j dominadas pelos programadores. Aperfeioamentos realizados nas tcnicas de imple-
mentao tambm foram de grande importncia para o emprego da lgica como linguagem de pro-
gramao. O primeiro interpretador experimental foi desenvolvido por um grupo de pesquisadores
liderados por Alain Colmerauer na Universidade de Aix-Marseille (1972) com o nome de Prolog, um
acrnimo para "Programmation en Logique". Seguindo-se a este primeiro passo, implementaes mais
"praticas" foram desenvolvidas por Battani e Meloni (1973), Bruynooghe (1976) e, principalmente,
David H. D. Warren, Lus Moniz Pereira e outros pesquisadores da Universidade de Edimburgo
(U.K.) que, em 1977, formalmente definiram o sistema hoje denominado "Prolog de Edimburgo",
usado como referncia para a maioria das atuais implementaes da linguagem Prolog. Deve-se tam-
bm a Warren a especificao da WAM (Warren Abstract Machine), um modelo formal empregado
at hoje na pesquisa de arquiteturas computacionais orientadas programao em lgica.
1.2 PROGRAMAO EM LGICA
Uma das principais idias da programao em lgica de que um algoritmo constitudo por dois
elementos disjuntos: a lgica e o controle. O componente lgico corresponde definio do que deve
ser solucionado, enquanto que o componente de controle estabelece como a soluo pode ser obtida.
O programador precisa somente descrever o componente lgico de um algoritmo, deixando o controle
3
da execuo para ser exercido pelo sistema de programao em lgica utilizado. Em outras palavras, a
tarefa do programador passa a ser simplesmente a especificao do problema que deve ser soluciona-
do, razo pela qual as linguagens lgicas podem ser vistas simultaneamente como linguagens para
especificao formal e linguagens para a programao de computadores.
Um programa em lgica ento a representao de determinado problema ou situao expressa atra-
vs de um conjunto finito de um tipo especial de sentenas lgicas denominadas clusulas. Ao contr-
rio de programas em Pascal ou C, um programa em lgica no a descrio de um procedimento para
se obter a soluo de um problema. Na realidade o sistema utilizado no processamento de programas
em lgica inteiramente responsvel pelo procedimento a ser adotado na sua execuo. Um programa
em lgica pode tambm ser visto alternativamente como uma base de dados, exceto que as bases de
dados convencionais descrevem apenas fatos tais como "Oscar um avestruz", enquanto que as sen-
tenas de um programa em lgica possuem um alcance mais genrico, permitindo a representao de
regras como em "Todo avestruz um pssaro", o que no possui correspondncia em bases de dados
convencionais. Na figura abaixo se procura explicitar as principais diferenas entre programao con-
vencional e programao em lgica.
PROGRAMAS CONVENCIONAIS PROGRAMAS EM LGICA
Processamento Numrico Processamento Simblico
Solues Algortmicas Solues Heursticas
Estruturas de Controle e Conhecimento Integradas Estruturas de Controle e Conhecimento Separadas
Difcil Modificao Fcil Modificao
Somente Respostas Totalmente Corretas Incluem Respostas Parcialmente Corretas
Somente a Melhor Soluo Possvel Incluem Todas as Solues Possveis
Figura 1.1 Programas Convencionais x Programas em Lgica
O paradigma fundamental da programao em lgica o da programao declarativa, em oposio
programao procedimental tpica das linguagens convencionais. A programao declarativa engloba
tambm a programao funcional, cujo exemplo mais conhecido a linguagem Lisp. Lembrando en-
tretanto que Lisp data de 1960, a programao funcional um estilo conhecido h bastante tempo, ao
contrrio da programao em lgica, que s ganhou mpeto a partir dos anos 80, quando foi escolhida
como a linguagem bsica do projeto japons para o desenvolvimento dos denominados computadores
de quinta gerao. O ponto focal da programao em lgica consiste em identificar a noo de com-
putao com a noo de deduo. Mais precisamente, os sistemas de programao em lgica reduzem
a execuo de programas pesquisa da refutao das sentenas do programa em conjunto com a ne-
gao da sentena que expressa a consulta, seguindo a regra: "uma refutao a deduo de uma
contradio".
Pode-se ento expressar conhecimento (programas e/ou dados) em Prolog por meio de clusulas de
dois tipos: fatos e regras
2
. Um fato denota uma verdade incondicional, enquanto que as regras defi-
nem as condies que devem ser satisfeitas para que uma certa declarao seja considerada verdadei-
ra. Como fatos e regras podem ser utilizados conjuntamente, nenhum componente dedutivo adicional
precisa ser utilizado. Alm disso, como regras recursivas e no-determinismo so permitidos, os pro-
gramadores podem obter descries muito claras, concisas e no-redundantes da informao que de-
sejam representar. Como no h distino entre argumentos de entrada e de sada, qualquer combina-
o de argumentos pode ser empregada.
Os termos "programao em lgica" e "programao Prolog" tendem a ser empregados indistinta-
mente. Deve-se, entretanto, destacar que a linguagem Prolog apenas uma particular abordagem da
programao em lgica. As caractersticas mais marcantes dos sistemas de programao em lgica em
geral - e da linguagem Prolog em particular - so as seguintes:

2
Ver o Apndice A para uma abordagem mais formal.
4
Especificaes so Programas: A linguagem de especificao entendida pela mquina e ,
por si s, uma linguagem de programao. Naturalmente, o refinamento de especificaes
mais efetivo do que o refinamento de programas. Um nmero ilimitado de clusulas diferentes
pode ser usado e predicados (procedimentos) com qualquer nmero de argumentos so poss-
veis. No h distino entre o programa e os dados. As clusulas podem ser usadas com grande
vantagem sobre as construes convencionais para a representao de tipos abstratos de dados.
A adequao da lgica para a representao simultnea de programas e suas especificaes a
torna um instrumento especialmente til para o desenvolvimento de ambientes e prottipos.
Capacidade Dedutiva: O conceito de computao confunde-se com o de (passo de) inferncia.
A execuo de um programa a prova do teorema representado pela consulta formulada, com
base nos axiomas representados pelas clusulas (fatos e regras) do programa.
No-determinismo: Os procedimentos podem apresentar mltiplas respostas, da mesma forma
que podem solucionar mltiplas e aleatoriamente variveis condies de entrada. Atravs de um
mecanismo especial, denominado "backtracking", uma seqncia de resultados alternativos
pode ser obtida.
Reversibilidade das Relaes: (Ou "computao bidirecional"). Os argumentos de um proce-
dimento podem alternativamente, em diferentes chamadas representar ora parmetros de entra-
da, ora de sada. Os procedimentos podem assim ser projetados para atender a mltiplos prop-
sitos. A execuo pode ocorrer em qualquer sentido, dependendo do contexto. Por exemplo, o
mesmo procedimento para inserir um elemento no topo de uma pilha qualquer pode ser usado,
em sentido contrrio, para remover o elemento que se encontrar no topo desta pilha.
Trplice Interpretao dos Programas em Lgica: Um programa em lgica pode ser seman-
ticamente interpretado de trs modos distintos: (1) por meio da semntica declarativa, inerente
lgica, (2) por meio da semntica procedimental, onde as clusulas dos programas so vistas
como entrada para um mtodo de prova e, (3) por meio da semntica operacional, onde as clu-
sulas so vistas como comandos para um procedimento particular de prova por refutao. Essas
trs interpretaes so intercambiveis segundo a particular abordagem que se mostrar mais
vantajosa ao problema que se tenta solucionar.
Recurso: A recurso, em Prolog, a forma natural de ver e representar dados e programas.
Entretanto, na sintaxe da linguagem no h laos do tipo "for" ou "while" (apesar de poderem
ser facilmente programados), simplesmente porque eles so absolutamente desnecessrios.
Tambm so dispensados comandos de atribuio e, evidentemente, o "goto". Uma estrutura de
dados contendo variveis livres pode ser retornada como a sada de um procedimento. Essas va-
riveis livres podem ser posteriormente instanciadas por outros procedimentos produzindo o
efeito de atribuies implcitas a estruturas de dados. Onde for necessrio, variveis livres so
automaticamente agrupadas por meio de referncias transparentes ao programador. Assim, as
variveis lgicas um potencial de representao significativamente maior do que oferecido por
operaes de atribuio e referncia nas linguagens convencionais.
A premissa bsica da programao em lgica portanto que "computao inferncia controlada".
Tal viso da computao tem se mostrado extremamente produtiva, na medida em que conduz idia
de que computadores podem ser projetados com a arquitetura de mquinas de inferncia. Grande parte
da pesquisa sobre computao paralela, conduzida hoje nos EUA, Europa e Japo, emprega a progra-
mao em lgica como instrumento bsico para a especificao de novas arquiteturas de hardware e o
desenvolvimento de mquinas abstratas no-convencionais.
1.3 APLICAES
Um dos primeiros usos da programao em lgica foi a representao e anlise de subconjuntos da
linguagem natural. Esta foi inclusive a aplicao que motivou Alain Colmerauer a desenvolver a pri-
5
meira implementao da linguagem Prolog. Logo em seguida, outros pesquisadores da rea da inteli-
gncia artificial propuseram diversas novas aplicaes para o novo instrumento. Alguns dos primeiros
trabalhos com Prolog envolviam a formulao de planos e a escrita de compiladores, por Pereira e
Warren (1977), prova de teoremas em geometria por R. Welhan (1976) e a soluo de problemas de
mecnica, por Bundy et al. (1979). As aplicaes relatadas desde ento, multiplicaram-se velozmente.
Concentraremos aqui a ateno em um conjunto das principais reas investigadas com o concurso da
programao em lgica.
Sistemas Baseados em Conhecimento (SBCs): Ou knowledge-based systems, so sistemas
que aplicam mecanismos automatizados de raciocnio para a representao e inferncia de co-
nhecimento. Tais sistemas costumam ser identificados como simplesmente "de inteligncia arti-
ficial aplicada" e representam uma abrangente classe de aplicaes da qual todas as demais se-
riam aproximadamente subclasses. A tecnologia dos SBCs foi identificada na Inglaterra pelo
Relatrio Alvey (1982) como uma das quatro tecnologias necessrias completa explorao
dos computadores de quinta gerao. As outras seriam: interface homem-mquina (MMI), inte-
grao de circuitos em ultra-grande escala (ULSI) e engenharia de software (SE). O relaciona-
mento entre SBCs e a nova gerao de computadores , na verdade, altamente simbitica, cada
uma dessas reas necessria para a realizao do completo potencial da outra.
Sistemas de Bases de Dados (BDs): Uma particularmente bem definida aplicao dos SBCs
so bases de dados. BDs convencionais tradicionalmente manipulam dados como colees de
relaes armazenadas de modo extensional sob a forma de tabelas. O modelo relacional serviu
de base implementao de diversos sistemas fundamentados na lgebra relacional, que ofere-
ce operadores tais como juno e projeo. O processador de consultas de uma BD convencio-
nal deriva, a partir de uma consulta fornecida como entrada, alguma conjuno especfica de
tais operaes algbricas que um programa gerenciador ento aplica s tabelas visando a recu-
perao de conjuntos de dados (n-tuplas) apropriados, se existirem. O potencial da programao
em lgica para a representao e consulta BDs foi simultaneamente investigado, em 1978, por
van Emden, Kowalski e Trnlund. As trs pesquisas estabeleceram que a recuperao de dados
- um problema bsico em BDs convencionais - intrnseca ao mecanismo de inferncia dos in-
terpretadores lgicos. Desde ento diversos sistemas tem sido propostos para a representao de
BDs por meio de programas em lgica.
Sistemas Especialistas (SEs): Um sistema especialista uma forma de SBC especialmente
projetado para emular a especializao humana em algum domnio especfico. Tipicamente um
SE ir possuir uma base de conhecimento (BC) formada de fatos, regras e heursticas sobre o
domnio, juntamente com a capacidade de entabular comunicao interativa com seus usurios,
de modo muito prximo ao que um especialista humano faria. Alm disso os SEs devem ser ca-
pazes de oferecer sugestes e conselhos aos usurios e, tambm, melhorar o prprio desempe-
nho a partir da experincia, isto , adquirir novos conhecimentos e heursticas com essa intera-
o. Diversos sistemas especialistas foram construdos com base na programao em lgica,
como por exemplo o sistema ORBI, para a anlise de recursos ambientais desenvolvido por Pe-
reira et al. na Universidade Nova de Lisboa.
Processamento da Linguagem Natural (PLN): O PLN da maior importncia para o desen-
volvimento de ferramentas para a comunicao homem-mquina em geral e para a construo
de interfaces de SBCs em particular. A implementao de sistemas de PLN em computadores
requer no somente a formalizao sinttica, como tambm - o grande problema - a formaliza-
o semntica, isto , o correto significado das palavras, sentenas, frases, expresses, etc. que
povoam a comunicao natural humana. O uso da lgica das clusulas de Horn
3
para este pro-
psito foi inicialmente investigado por Colmerauer, o prprio criador do Prolog (1973), e poste-
riormente por Kowalski (1974). Ambos mostraram (1) que as clusulas de Horn eram adequa-
das representao de qualquer gramtica livre-de-contexto (GLC), (2) permitiam que ques-

3
Assim denominadas em homenagem a Alfred Horn, que primeiro lhes estudou as propriedades, em 1951.
6
tes sobre a estrutura de sentenas em linguagem natural fossem formuladas como objetivos ao
sistema, e (3) que diferentes procedimentos de prova aplicados a representaes lgicas da lin-
guagem natural correspondiam a diferentes estratgias de anlise.
Educao: A programao em lgica poder vir a oferecer no futuro uma contribuio bastante
significativa ao uso educacional de computadores. Esta proposta foi testada em 1978 quando
Kowalski introduziu a programao em lgica na Park House Middle School em Wimbledon,
na Inglaterra, usando acesso on-line aos computadores do Imperial College. O sucesso do em-
preendimento conduziu a um projeto mais abrangente denominado "Lgica como Linguagem
de Programao para Crianas", inaugurado em 1980 na Inglaterra com recursos do Conselho
de Pesquisa Cientfica daquele pas. Os resultados obtidos desde ento tem mostrado que a pro-
gramao em lgica no somente assimilada mais facilmente do que as linguagens convenci-
onais, como tambm pode ser introduzida at mesmo a crianas na faixa dos 10 a 12 anos, as
quais ainda se beneficiam do desenvolvimento do pensamento lgico-formal que o uso de lin-
guagens como o Prolog induz.
Arquiteturas No-Convencionais: Esta rea vem se tornando cada vez mais um campo extre-
mamente frtil para o uso da programao em lgica especialmente na especificao e imple-
mentao de mquinas abstratas de processamento paralelo. O paralelismo pode ser modelado
pela programao em lgica em variados graus de atividade se implementado em conjunto com
o mecanismo de unificao. Duas implementaes iniciais nesse sentido foram o Parlog, des-
envolvido em 1984 por Clark e Gregory, e o Concurrent Prolog (CP), por Shapiro em 1983. O
projeto da Quinta Gerao, introduzido na prxima seo, foi fortemente orientado ao uso da
programao em lgica em sistemas de processamento paralelo.
Muitas outras aplicaes poderiam ainda ser citadas, principalmente na rea da inteligncia artificial,
que tem no Prolog e no Lisp as suas duas linguagens mais importantes. Novas tecnologias de hardwa-
re e software tais como sistemas massivamente paralelos, redes de computadores, assistentes inteli-
gentes, bases de dados semnticas, etc., tornam o uso do Prolog (e de outras linguagens baseadas em
lgica) cada vez mais atraentes
1.4 A QUINTA GERAO
Em 1979 o governo japons iniciou estudos para um novo, ambicioso e nico projeto na rea da com-
putao normalmente denominado Sistemas Computacionais de Quinta Gerao cujo objetivo princi-
pal era o desenvolvimento, no espao de uma dcada, de hardware e software de alto desempenho,
caracterizando uma nova gerao de computadores. O projeto iniciou em 1982 e foi oficialmente en-
cerrado em maio de 1992. Muito foi dito e escrito sobre o projeto, que produziu inmeros resultados e
diversos subprodutos ao longo desses dez anos. Um de seus principais mritos, entretanto, parece ter
sido chamar a ateno da comunidade cientfica mundial para as potencialidades da lgica como lin-
guagem de programao de computadores. Sistemas de processamento lgico paralelo derivados do
Prolog foram desenvolvidos para servir como linguagens-ncleo (kernel languages) dos novos equi-
pamentos que seriam produzidos a partir dos resultados do projeto. Considerado um sucesso por seus
dirigentes, o projeto foi entretanto criticado por no haver conseguido colocar as tecnologias desen-
volvidas disposio do grande pblico. Em outras palavras: ainda no dispomos hoje (1994) de mi-
crocomputadores pessoais de quinta gerao - denominados mquinas PSI (Personal Sequential Infe-
rence machines) - comercialmente viveis para o grande pblico. Os resultados tericos obtidos e os
prottipos construdos foram entretanto de grande valia para que num futuro prximo isso venha a ser
possvel. Nestas novas mquinas o papel da linguagem assembly ser desempenhado por um dialeto
do Prolog orientado ao processamento paralelo.
Um relatrio sobre o projeto, organizado por Ehud Shapiro e David Warren em 1993, reuniu as opini-
es de diversos pesquisadores dele participantes, entre os quais Kazuhiro Fuchi, seu lder, Robert
Kowalski, Koichi Furukawa, Kazunori Ueda e outros. Todos os depoimentos foram unnimes em
7
declarar que os objetivos do projeto foram plenamente atingidos. Na Figura 1.2 mostrada uma
adaptao em portugus do diagrama "de intenes" apresentado por Fuchi, no Fifth Generation
Computer Systems Congress de 1981 (FGCS'81), o congresso que deu a conhecer ao mundo um dos
mais ambiciosos projetos da histria da computao.
ANO 1 ANO 5 ANO 10
Network --- tica ---
Personal Inference Machine (Reduo a chips)
Mquina Prolog +
(Novo Software)
LISP
APL
Smalltalk
PS, etc.
Programao:
em lgica e
funcional
(comparveis s mquinas
de grande porte de 1981)
Ambientes de Programao Inteligentes
Ambientes de Projeto Orientados Prototipagem
Mquinas Altamente Configurveis (Chips e Mdulos)
Supermquinas (Realmente Inteligentes)
Nova Linguagem
5G Core Language
(INFERENCE MACHINE)
Data Flow Machine
Database Machine
Paralelismo
Associatividade
SOFTWARE -----------> Engenharia de Conhecimento
(Acumulao) --------------------------------------------------------->
Engenharia de Software (Teorias Bsicas)
Pesquisa em Inteligncia Artificial
Soluo de Problemas:
Bases de Conhecimento:
Simbolismo em Alto
Nvel:
Planejamento
Programao
Prova de Teoremas
Jogos
Entendimento da
Linguagem Natural
Consultas
Figura 1.2 Diagrama Conceitual do Projeto do Computador de Quinta Gerao
Segundo o relatrio de Shapiro e Warren, um dos primeiros passos do projeto consistiu em definir
uma linguagem de programao em lgica que ao mesmo tempo fosse adequada ao paralelismo do
hardware e aos requisitos sofisticados especificados para o software. Baseada no Parlog e no Cuncur-
rent Prolog, uma equipe de pesquisadores liderada por Kazunori Ueda desenvolveu a linguagem GHC
(Guarded Horn Clauses), que deu origem KL0 (Kernel Language Zero). Um refinamento dessa ver-
so beta
4
, realizado pela equipe de Takashi Chikayama produziu, em 1987, a linguagem KL1. Todos
os sub-projetos do FGCS foram revistos para trabalhar com essa linguagem. Em 1988 os primeiros
prottipos do computador de quinta gerao foram construdos, recebendo o nome genrico de Pa-
rallel Inference Machines (PIMs). Tais computadores possuiam arquitetura massivamente paralela e
tinham velocidade de processamento calculada em MLIPS (milhes de inferncias lgicas por segun-
do). Uma dessas mquinas, denominada Multi-PSI foi apresentada com grande sucesso no FGCS'88.

4
Uma verso distribuida a grupos selecionados de usurios para teste e depurao.
8
A linguagem KL1 foi empregada para escrever o sistema operacional PIMOS (Parallel Inference Ma-
chine Operating System), em 1988. importante ressaltar aqui que a linguagem KL1 uma lingua-
gem de muito alto nvel
5
e, ao mesmo tempo, uma linguagem de mquina, isto , adequada progra-
mao a nvel de registradores, posies de memria e portas lgicas. As verses mais recentes do
PIMOS provam definitivamente que KL1 (agora j KL2) uma linguagem muito mais adequada do
que as linguagens convencionais para a construo de software bsico em mquinas paralelas. Outras
linguagens de programao foram - e ainda vem sendo - pesquisadas. Por exemplo, uma linguagem de
programao em lgica com restries denominada GDCC foi projetada em um nvel ainda mais alto
que a KL1. Uma outra linguagem, denominada "Quixote" foi produzida para lidar com bases de dados
dedutivas e orientadas a objetos. Para o gerenciamento de sistemas paralelos distribudos foi especifi-
cada a linguagem Kappa-P. Todas essas linguagens, com as quais - ou com seus dialetos - todos cer-
tamente estaremos em contato num futuro prximo, esto baseadas nos conceitos e resultados da pes-
quisa em programao em lgica.
Tecnicamente considera-se que o projeto atingiu a primeira parte de seus objetivos: diversos compu-
tadores paralelos foram construdos. Tais computadores so denominados coletivamente de mquinas
de inferncia paralela (PIMs), incorporam a linguagem KL1 e o sistema operacional PIMOS. Alm
disso as mquinas PIM mais recentemente construdas lograram atingir um pico de desempenho da
ordem de 1 gigalips (1 bilho de inferncias lgicas por segundo), o que era um dos objetvos con-
cretos do projeto considerados mais difceis de atingir.
A segunda parte do projeto, entretanto, a construo de mquinas orientadas bases de dados (data-
base machines) foi menos claramente abordada. Tal objetivo foi reformulado a partir do sucesso obti-
do com a construo de linguagens de programao em lgica concorrente para a construo de im-
plementaes baseadas em KL1 na mesma plataforma de hardware das mquinas PIM.
De um modo geral, entretanto, considera-se que o projeto demonstrou ser a tecnologia PIM bem suce-
dida em novas aplicaes envolvendo paralelismo em diversas reas, especialmente computao no-
numrica e inteligncia artificial. Em suma, segundo o relatrio Shapiro-Warren:
"(...) uma ponte foi construda entre a computao paralela e as aplicaes envolvendo inte-
ligncia artificial. Entretanto, as duas extremidades finais da ponte ainda se encontram por
concluir e a ponte em si mais frgil do que poderia ter sido. sem dvida ainda muito cedo
para se esperar que a ponte seja inaugurada recebendo uma grande aclamao."
1.5 PORQUE ESTUDAR PROLOG
Normalmente h um gap de 10 a 20 anos entre o estgio bsico de uma pesquisa tecnolgica e o mo-
mento em que esta colocada disposio da sociedade consumidora. Na rea de informtica esse
intervalo costuma ser menor, entretanto, estamos assistindo a uma completa transformao: do para-
digma da quarta gerao, ora em fase de esgotamento
6
para arquiteturas inovadoras, contemplando
sistemas de processamento paralelo, a concorrncia de processos e layers baseados em lgica. A
grande exploso da informtica atualmente persegue conceitos tais como interoperabilidade, conecti-
vidade, orientao a objetos, sistemas multimdia, agentes inteligentes cooperativos, hiperdocumen-
tos, realidade virtual, inteligncia de mquina e outros, cuja evoluo ir determinar nos prximos
anos uma mudana to radical quanto foi a das carruagens para os veculos automotores - mais ainda,
segundo alguns autores, - terminando por transformar completamente a prpria estrutura social.
A programao Prolog uma excelente porta de entrada para a informtica do futuro, tendo em vista

5
Quanto mais alto o nvel de uma linguagem, mais prxima da linguagem natural ela se encontra.
6
As atuais tecnologias de integrao de circuitos (VLSI/ULSI) tendem a atingir os limites fsicos alm dos quais se tornam
economicamente inviveis.
9
que, entre outras vantagens:
(1) de aprendizado muito mais fcil e natural do que as linguagens procedimentais convencio-
nais, podendo inclusive ser ministrada a estudantes entre o final do primeiro e o incio do se-
gundo grau com grande aproveitamento;
(2) Implementa com preciso todos os novos modelos surgidos nos ltimos anos, inclusive redes
neurais, algoritmos genticos, sociedades de agentes inteligentes, sistemas concorrentes e pa-
ralelos;
(3) Permite a implementao de extenses, inclusive em nvel meta, e a definio precisa de siste-
mas reflexivos (essenciais, por exemplo, robtica);
(4) Libera o programador dos problemas associados ao controle de suas rotinas, permitindo-lhe
concentrar-se nos aspectos lgicos da situao a representar.
Tem sido observada a tendncia de substituio paulatina no mercado de trabalho dos servios de
programao pelos de especificao. Isso ocorre por vrias razes, dentre elas porque as especifica-
es podem ser formalmente provadas corretas, o que no ocorre com facilidade nos programas con-
vencionais. Essa transio - da arte de programar cincia de especificar - vem estimulando o apare-
cimento de linguagens como o Prolog, que pode ser visto como sendo simultaneamente uma lingua-
gem de programao e de especificao (ou, como querem alguns, como uma linguagem de especifi-
caes diretamente executveis em computadores).
Vem tambm ocorrendo aceleradamente a popularizao de ambientes e interfaces cada vez mais
prximos do usurio final e oferecendo recursos muito poderosos para a personalizao de programas
de acordo com as preferncias individuais. Isso permite supor que, num futuro prximo, qualquer
pessoa, mesmo sem formao especfica em programao, poder interagir facilmente com computa-
dores, em nveis muito elevados
7
, dispensando em grande parte a programao, tal como hoje co-
nhecida. Por outro lado, a construo de tais ambientes ira depender de profissionais bem mais prepa-
rados do que um programador em Pascal, por exemplo. Devero, tais profissionais, possuir um curr-
culo muito mais rico, abrangendo a teoria da computao, lgica matemtica, lgebra relacional, filo-
sofia, arquiteturas concorrentes e paralelas, etc. Sero necessrios entretanto em nmero muito maior
do que se imaginava no incio dos anos 80, quando essa tendncia ainda no se apresentava perfeita-
mente delineada, uma vez que praticamente todo software colocado no mercado dever ser produzido
a partir de suas especificaes formais.
Um ltimo motivo - no menos importante que os demais j apresentados - deve ainda ser considera-
do: A expressividade herdada da lgica torna a linguagem Prolog um instrumento especialmente po-
deroso, adequado para a descrio do mundo real com todos os seus contornos, nuances e sutilezas.
Nos poucos casos em que a representao se torna mais difcil - na representao temporal, por exem-
plo - a flexibilidade do Prolog em aceitar o desenvolvimento de extenses semanticamente precisas e
incorpor-las ao seu mecanismo de produo de inferncias, remove qualquer impedimento para o seu
emprego em virtualmente qualquer rea do conhecimento.
RESUMO
A programao em lgica, tal como a conhecemos hoje, tem suas razes no clculo de predica-
dos, proposto por Frege em 1879. Diversos estudos posteriores foram de grande importncia
para sua evoluo, com destaque para as investigaes de Herbrand, Gdel, Tarski, Prawitz,
Robinson e Green;
A primeira implementao da linguagem Prolog foi realizada por Alain Colmerauer e sua equi-

7
Ao nvel da linguagem coloquial falada ou escrita, por exemplo.
10
pe, na Universidade de Aix-Marseille em 1972. A formalizao semntica da programao com
clusulas de Horn devida a Kowalski (1974) e a especificao do primeiro "standard" - o
Prolog de Edimburgo - foi realizada por Warren e Pereira em 1977;
As principais caractersticas que diferenciam os programas em lgica dos programas convenci-
onais so as seguintes:
(1) Processamento simblico,
(2) Solues heursticas,
(3) Estruturas de controle e conhecimento separadas,
(4) Fcil modificao,
(5) Incluem respostas parcialmente corretas, e
(6) Incluem todas as solues possveis;
Alm disso, os sistemas de programao em lgica em geral e a linguagem Prolog em particular
possuem as seguintes propriedades:
(1) Funcionam simultaneamente como linguagem de programao e de especificao,
(2) Possuem capacidade dedutiva,
(3) Operam de forma no-determinstica,
(4) Permitem a representao de relaes reversveis,
(5) Permitem interpretao declarativa, procedimental e operacional, e
(6) So naturalmente recursivos;
As principais aplicao da programao em lgica so:
(1) Sistemas Baseados em Conhecimento SBCs),
(2) Sistemas de Bases de Dados (BDs),
(3) Sistemas Especialistas (SEs),
(4) Processamento da Linguagem Natural (PLN),
(5) Educao, e
(6) Modelagem de Arquiteturas No-Convencionais;
O projeto japons para o desenvolvimento de Sistemas Computacionais de Quinta Gerao ini-
ciou em 1982 e foi oficialmente concludo em maio de 1992. Apesar de ficarem aqum do espe-
rado, os resultados produzidos permitem claramente antever o papel preponderante que a pro-
gramao em lgica dever representar nos futuros sistemas computacionais;
A crescente necessidade de garantir a qualidade do software substituindo programas por especi-
ficaes formais diretamente executveis, aliada evoluo das caractersticas do hardware,
que passam a explorar cada vez mais os conceitos de concorrncia e paralelismo, tornam a lin-
guagem Prolog uma excelente porta de entrada para a informtica do futuro.
11
2. A LINGUAGEM PROLOG
A principal utilizao da linguagem Prolog reside no domnio da programao simblica, no-
numrica, sendo especialmente adequada soluo de problemas, envolvendo objetos e relaes entre
objetos. O advento da linguagem Prolog reforou a tese de que a lgica um formalismo conveniente
para representar e processar conhecimento. Seu uso evita que o programador descreva os procedi-
mentos necessrios para a soluo de um problema, permitindo que ele expresse declarativamente
apenas a sua estrutura lgica, atravs de fatos, regras e consultas. Algumas das principais caractersti-
cas da linguagem Prolog so:
uma linguagem orientada ao processamento simblico;
Representa uma implementao da lgica como linguagem de programao;
Apresenta uma semntica declarativa inerente lgica;
Permite a definio de programas reversveis, isto , programas que no distinguem entre os
argumentos de entrada e os de sada;
Permite a obteno de respostas alternativas;
Suporta cdigo recursivo e iterativo para a descrio de processos e problemas, dispensando os
mecanismos tradicionais de controle, tais como while, repeat, etc;
Permite associar o processo de especificao ao processo de codificao de programas;
Representa programas e dados atravs do mesmo formalismo;
Incorpora facilidades computacionais extralgicas e metalgicas.
No presente captulo introduz-se informalmente os conceitos essenciais da linguagem Prolog, visando
conduzir rapidamente o leitor ao domnio da sintaxe e a um entendimento intuitivo da semntica asso-
ciada aos programas.
2.1 FATOS
Considere a rvore genealgica mostrada na Figura 2.1. possvel definir, entre os objetos (indivdu-
os) mostrados, uma relao denominada progenitor que associa um indivduo a um dos seus progeni-
tores. Por exemplo, o fato de que Joo um dos progenitores de Jos pode ser denotado por:
progenitor(joo, jos).
onde progenitor o nome da relao e joo e jos so os seus argumentos. Por razes que se tornaro
claras mais tarde, escreve-se aqui nomes de pessoas (como Joo) iniciando com letra minscula. A
relao progenitor completa, como representada na figura acima pode ser definida pelo seguinte pro-
grama Prolog:
progenitor(maria, jos).
progenitor(joo, jos).
progenitor(joo, ana).
progenitor(jos, jlia).
progenitor(jos, ris).
progenitor(ris, jorge).
O programa acima compe-se de seis clusulas, cada uma das quais denota um fato acerca da relao
progenitor. Se o programa for submetido a um sistema Prolog, este ser capaz de responder algumas
questes sobre a relao ali representada. Por exemplo: "Jos o progenitor de ris?". Uma consulta
como essa deve ser formulada ao sistema precedida por um "?-". Esta combinao de sinais denota
que se est formulando uma pergunta. Como h um fato no programa declarando explicitamente que
12
Jos o progenitor de ris, o sistema responde "sim".
?-progenitor(jos, ris).
sim
Maria Joo
Jos Ana
Jlia ris
Jorge
Figura 2.1 Uma rvore genealgica
Uma outra questo poderia ser: "Ana um dos progenitores de Jorge?". Nesse caso o sistema respon-
de "no", porque no h nenhuma clusula no programa que permita deduzir tal fato.
?-progenitor(ana, jorge).
no
A questo "Lus progenitor de Maria?" tambm obteria a resposta "no", porque o programa nem
sequer conhece algum com o nome Lus.
?-progenitor(lus, maria).
no
Perguntas mais interessantes podem tambm ser formuladas, por exemplo: "Quem progenitor de
ris?". Para fazer isso introduz-se uma varivel, por exemplo "X" na posio do argumento corres-
pondente ao progenitor de ris. Desta feita o sistema no se limitar a responder "sim" ou "no", mas
ir procurar (e informar caso for encontrado) um valor de X que torne a assertiva "X progenitor de
ris" verdadeira.
?-progenitor(X, ris).
X=jos
Da mesma forma a questo "Quem so os filhos de Jos?" pode ser formulada com a introduo de
uma varivel na posio do argumento correspondente ao filhos de Jos. Note que, neste caso, mais de
uma resposta verdadeira pode ser encontrada. O sistema ir fornecer a primeira que encontrar e
aguardar manifestao por parte do usurio. Se este desejar outras solues deve digitar um ponto-e-
vrgula (;), do contrrio digita um ponto (.), o que informa ao sistema que a soluo fornecida sufi-
ciente.
?-progenitor(jos, X).
X=jlia;
X=ris;
no
Aqui a ltima resposta obtida foi "no" significando que todas as solues vlidas j foram forneci-
das. Uma questo mais geral para o programa seria: "Quem progenitor de quem?" ou, com outra
formulao: "Encontre X e Y tal que X progenitor de Y". O sistema, em resposta, ir fornecer (en-
quanto se desejar, digitando ";") todos os pares progenitor-filho at que estes se esgotem (quando
ento responde "no") ou at que se resolva encerrar a apresentao de novas solues (digitando ".").
No exemplo a seguir iremos nos satisfazer com as trs primeiras solues encontradas.
?-progenitor(X, Y).
13
X=maria Y=jos;
X=joo Y=jos;
X=joo Y=ana.
Pode-se formular questes ainda mais complicadas ao programa, como "Quem so os avs de Jor-
ge?". Como nosso programa no possui diretamente a relao av, esta consulta precisa ser dividida
em duas etapas, como pode ser visto na Figura 2.2. A saber:
(1) Quem progenitor de Jorge? (Por exemplo, Y) e
(2) Quem progenitor de Y? (Por exemplo, X)
Esta consulta em Prolog escrita como uma seqncia de duas consultas simples, cuja leitura pode
ser: "Encontre X e Y tais que X progenitor de Y e Y progenitor de Jorge".
?-progenitor(X, Y), progenitor(Y, jorge).
X=jos Y=ris
X
Y
Jorge
progenitor
progenitor
av
Figura 2.2 A relao av em funo de progenitor
Observe que se mudarmos a ordem das consultas na composio, o significado lgico permanece o
mesmo, apesar do resultado ser informado na ordem inversa:
?-progenitor(Y, jorge), progenitor(X, Y).
Y=ris X=jos
De modo similar podemos perguntar: "Quem neto de Joo?":
?-progenitor(joo, X), progenitor(X, Y).
X=jos Y=jlia;
X=jos Y=ris.
Ainda uma outra pergunta poderia ser: "Jos e Ana possuem algum progenitor em comum?". Nova-
mente necessrio decompor a questo em duas etapas, formulando-a alternativamente como: "En-
contre um X tal que X seja simultaneamente progenitor de Jos e Ana".
?-progenitor(X, jos), progenitor(X, ana).
X=joo
Por meio dos exemplos apresentados at aqui acredita-se ter sido possvel ilustrar os seguintes pontos:
Uma relao como progenitor pode ser facilmente definida em Prolog estabelecendo-se as tu-
plas de objetos que satisfazem a relao;
O usurio pode facilmente consultar o sistema Prolog sobre as relaes definidas em seu pro-
grama;
Um programa Prolog constitudo de clusulas, cada uma das quais encerrada por um ponto
(.);
Os argumentos das relaes podem ser objetos concretos (como jlia e ris) ou objetos genri-
cos (como X e Y). Objetos concretos em um programa so denominados tomos, enquanto que
os objetos genricos so denominados variveis;
14
Consultas ao sistema so constitudas por um ou mais objetivos, cuja seqncia denota a sua
conjuno;
Uma resposta a uma consulta pode ser positiva ou negativa, dependendo se o objetivo corres-
pondente foi alcanado ou no. No primeiro caso dizemos que a consulta foi bem-sucedida e,
no segundo, que a consulta falhou;
Se vrias respostas satisfizerem a uma consulta, ento o sistema Prolog ir fornecer tantas
quantas forem desejadas pelo usurio.
2.2 REGRAS
O programa da rvore genealgica pode ser facilmente ampliado de muitas maneiras interessantes.
Inicialmente vamos adicionar informao sobre o sexo das pessoas ali representadas. Isso pode ser
feito simplesmente acrescentando os seguintes fatos ao programa:
masculino(joo).
masculino(jos).
masculino(jorge).
feminino(maria).
feminino(jlia).
feminino(ana).
feminino(ris).
As relaes introduzidas no programa so masculino e feminino . Tais relaes so unrias, isto ,
possuem um nico argumento. Uma relao binria, como progenitor, definida entre pares de obje-
tos, enquanto que as relaes unrias podem ser usadas para declarar propriedades simples desses
objetos. A primeira clusula unria da relao masculino pode ser lida como: "Joo do sexo mascu-
lino". Poderia ser conveniente declarar a mesma informao presente nas relaes unrias masculino e
feminino em uma nica relao binria sexo:
sexo(joo, masculino).
sexo(maria, feminino).
sexo(jos, masculino). ... etc.
A prxima extenso ao programa ser a introduo da relao filho como o inverso da relao proge-
nitor. Pode-se definir a relao filho de modo semelhante utilizada para definir a relao progenitor,
isto fornecendo uma lista de fatos, cada um dos quais fazendo referncia a um par de pessoas tal que
uma seja filho da outra. Por exemplo:
filho(jos, joo).
Entretanto podemos definir a relao "filho" de uma maneira muito mais elegante, fazendo o uso do
fato de que ela o inverso da relao progenitor e esta j est definida. Tal alternativa pode ser base-
ada na seguinte declarao lgica:
Para todo X e Y
Y filho de X se
X progenitor de Y.
Essa formulao j se encontra bastante prxima do formalismo adotado em Prolog. A clusula cor-
respondente, com a mesma leitura acima, :
filho(Y, X) :- progenitor(X, Y).
que tambm pode ser lida como: "Para todo X e Y, se X progenitor de Y, ento Y filho de X".
Clusulas Prolog desse tipo so denominadas regras. H uma diferena importante entre regras e fa-
tos. Um fato sempre verdadeiro, enquanto regras especificam algo que "pode ser verdadeiro se al-
gumas condies forem satisfeitas". As regras tem:
Uma parte de concluso (o lado esquerdo da clusula), e
15
Uma parte de condio (o lado direito da clusula).
O smbolo ":-" significa "se" e separa a clusula em concluso, ou cabea da clusula, e condio ou
corpo da clusula, como mostrado no esquema abaixo. Se a condio expressa pelo corpo da clu-
sula - progenitor (X, Y) - verdadeira ento, segue como conseqncia lgica que a cabea - filho(Y,
X) - tambm o . Por outro lado, se no for possvel demonstrar que o corpo da clusula verdadeiro,
o mesmo ir se aplicar cabea.
filho(Y, X) :- progenitor(X, Y)
A maioria dos sistemas Prolog, na ausncia de caracteres ASCII adequados, emprega o smbolo com-
posto ":-" para denotar a implicao "". Aqui, por uma questo de clareza, adotaremos este ltimo
smbolo, que o normalmente empregado na programao em lgica com clusulas definidas.
A utilizao das regras pelo sistema Prolog ilustrada pelo seguinte exemplo: vamos perguntar ao
programa se Jos filho de Maria:
?-filho(jos, maria).
No h nenhum fato a esse respeito no programa, portanto a nica forma de considerar esta questo
aplicando a regra correspondente. A regra genrica, no sentido de ser aplicvel a quaisquer objetos
X e Y. Logo pode ser aplicada a objetos particulares, como jos e maria. Para aplicar a regra, Y ser
substitudo por jos e X por maria. Dizemos que as variveis X e Y se tornaram instanciadas para:
X=maria e Y=jos
A parte de condio se transformou ento no objetivo progenitor(maria, jos). Em seguida o sistema
passa a tentar verificar se essa condio verdadeira. Assim o objetivo inicial, filho(jos, maria), foi
substitudo pelo sub-objetivo progenitor(maria, jos). Esse novo objetivo apresenta-se como trivial,
uma vez que h um fato no programa estabelecendo exatamente que Maria um dos progenitores de
Jos. Isso significa que a parte de condio da regra verdadeira, portanto a parte de concluso tam-
bm verdadeira e o sistema responde "sim".
Vamos agora adicionar mais algumas relaes ao nosso programa. A especificao, por exemplo, da
relao me entre dois objetos do nosso domnio pode ser escrita baseada na seguinte declarao lgi-
ca:
Para todo X e Y
X me de Y se
X progenitor de Y e
X feminino.
que, traduzida para Prolog, conduz seguinte regra:
me(X, Y) :- progenitor(X, Y), feminino(X).
onde a vrgula entre as duas condies indica a sua conjuno, significando que, para satisfazer o
corpo da regra, ambas as condies devem ser verdadeiras. A relao av, apresentada anteriormente
na Figura 2.2, pode agora ser definida em Prolog por:
av(X, Z) :- progenitor(X, Y), progenitor(Y, Z).
Neste ponto interessante comentar alguma coisa sobre o layout dos programas Prolog. Estes podem
ser escritos quase que com total liberdade, de modo que podemos inserir espaos e mudar de linha
onde e quando melhor nos aprouver. Em geral, porm, desejamos produzir programas de boa aparn-
cia, elegantes e sobretudo fceis de ser lidos. Com essa finalidade, normalmente se prefere escrever a
cabea da clusula e os objetivos da condio cada um em uma nova linha. Para destacar a concluso,
identamos os objetivos. A clusula av, por exemplo, seria escrita:
av(X, Z) :-
progenitor(X, Y),
progenitor(Y, Z).
16
Adicionaremos ainda uma ltima relao ao nosso programa para exemplificar mais uma particulari-
dade da linguagem Prolog. Uma clusula para a relao irm se embasaria na seguinte declarao
lgica:
Para todo X e Y
X irm de Y se
X e Y possuem um progenitor comum e
X do sexo feminino.
Ou, sob a forma de regra Prolog:
irm(X, Y) :-
progenitor(Z, X),
progenitor(Z, Y),
feminino(X).
Deve-se atentar para a forma sob a qual o requisito "X e Y possuem um progenitor comum" foi expres-
sa. A seguinte formulao lgica foi adotada: "Algum Z deve ser progenitor de X e esse mesmo Z deve
tambm ser progenitor de Y". Uma forma alternativa, porm menos elegante, de representar a mesma
condio seria: "Z1 progenitor de X e Z2 progenitor de Y e Z1 igual a Z2". Se consultarmos o
sistema com "Jlia irm de ris?" , obteremos, como esperado, um "sim" como resposta. Podera-
mos ento concluir que a relao irm, conforme anteriormente definida, funciona corretamente, en-
tretanto, h uma falha muito sutil que se revela quando perguntamos: "Quem irm de ris?". O sis-
tema ir nos fornecer duas respostas:
?-irm(X, ris).
X=jlia;
X=ris
dando a entender que ris irm de si prpria. Isso no certamente o que se tinha em mente na defi-
nio de irm, entretanto, de acordo com a regra formulada, a resposta obtida pelo sistema perfeita-
mente lgica. Nossa regra sobre irms no menciona que X e Y no devem ser os mesmos para que X
seja irm de Y. Como isso no foi requerido, o sistema, com toda razo, assume que X e Y podem
denotar a mesma pessoa e ir achar que toda pessoa do sexo feminino que possui um progenitor
irm de si prpria.
Para corrigir esta distoro necessrio acrescentar a condio de que X e Y devem ser diferentes.
Isso pode ser feito de diversas maneiras, conforme se ver mais adiante. Por enquanto vamos assumir
que uma relao diferente(X, Y) seja reconhecida pelo sistema como verdadeira se e somente se X e Y
no forem iguais. A regra para a relao irm fica ento definida por:
irm(X, Y) :-
progenitor(Z, X),
progenitor(Z,Y),
feminino(X),
diferente(X, Y).
Os pontos mais importantes vistos na presente seo foram:
Programas Prolog podem ser ampliados pela simples adio de novas clusulas;
As clusulas Prolog podem ser de trs tipos distintos: fatos, regras e consultas;
Os fatos declaram coisas que so incondicionalmente verdadeiras;
As regras declaram coisas que podem ser ou no verdadeiras, dependendo da satisfao das
condies dadas;
Por meio de consultas podemos interrogar o programa acerca de que coisas so verdadeiras;
As clusulas Prolog so constitudas por uma cabea e um corpo. O corpo uma lista de objeti-
vos separados por vrgulas que devem ser interpretadas como conjunes;
Fatos so clusulas que s possuem cabea, enquanto que as consultas s possuem corpo e as
regras possuem cabea e corpo;
17
Ao longo de uma computao, uma varivel pode ser substituda por outro objeto. Dizemos
ento que a varivel est instanciada;
As variveis so assumidas como universalmente quantificadas nas regras e nos fatos e existen-
cialmente quantificadas nas consultas
2.3 CONSTRUES RECURSIVAS
Iremos adicionar agora ao programa a relao antepassado, que ser definida a partir da relao pro-
genitor. A definio necessita ser expressa por meio de duas regras, a primeira das quais definir os
antepassados diretos (imediatos) e a segunda os antepassados indiretos. Dizemos que um certo X
antepassado indireto de algum Z se h uma cadeia de progenitura entre X e Z como ilustrado na
Figura 2.3. Na rvore genealgica da Figura 2.1, Joo antepassado direto de Ana e antepassado indi-
reto de Jlia.
A primeira regra, que define os antepassados diretos, bastante simples e pode ser formulada da se-
guinte maneira:
Para todo X e Z
X antepassado de Z se
X progenitor de Z.
Maria Joo
Jlia ris
Jorge
progenitor progenitor
progenitor (a)
(b)
antepassado direto
antepassado indireto
Figura 2.3 Exemplos da relao antepassado
ou, traduzindo para Prolog:
antepassado(X, Z) :-
progenitor(X, Z).
Por outro lado, a segunda regra mais complicada, porque a cadeia de progenitores poderia se esten-
der indefinidamente. Uma primeira tentativa seria escrever uma clusula para cada posio possvel
na cadeia. Isso conduziria a um conjunto de clusulas do tipo:
antepassado(X, Z) :-
progenitor(X, Y),
progenitor(Y, Z).
antepassado(X, Z) :-
progenitor(X, Y1),
progenitor(Y1, Y2),
progenitor(Y2, Z).
antepassado(X, Z) :-
progenitor(X, Y1),
progenitor(Y1, Y2),
progenitor(Y2, Y3),
progenitor(Y3, Z). ... etc.
Isso conduziria a um programa muito grande e que, de qualquer modo, somente funcionaria at um
determinado limite, isto , somente forneceria antepassados at uma certa profundidade na rvore
18
genealgica de uma famlia, porque a cadeia de pessoas entre o antepassado e seu descendente seria
limitada pelo tamanho da maior clusula definindo essa relao. H entretanto uma formulao ele-
gante e correta para a relao antepassado que no apresenta qualquer limitao. A idia bsica
definir a relao em termos de si prpria, empregando um estilo de programao em lgica denomina-
do recursivo:
Para todo X e Z
X antepassado de Z se
existe um Y tal que
X progenitor de Y e
Y antepassado de Z.
A clusula Prolog correspondente :
antepassado(X, Z) :-
progenitor(X, Y),
antepassado(Y, Z).
Assim possvel construir um programa completo para a relao antepassado composto de duas re-
gras: uma para os antepassados diretos e outra para os indiretos. Reescrevendo as duas juntas tem-se:
antepassado(X, Z) :-
progenitor(X, Z).
antepassado(X, Z) :-
progenitor(X, Y),
antepassado(Y, Z).
Tal definio pode causar certa surpresa, tendo em vista a seguinte pergunta: Como possvel ao de-
finir alguma coisa empregar essa mesma coisa se ela ainda no est completamente definida? Tais
definies so denominadas recursivas e do ponto de vista da lgica so perfeitamente corretas e inte-
ligveis, o que deve ficar claro, pela observao da Figura 2.4. Por outro lado o sistema Prolog deve
muito do seu potencial de expressividade capacidade intrnseca que possui de utilizar facilmente
definies recursivas. O uso de recurso , em realidade, uma das principais caractersticas herdadas
da lgica pela linguagem Prolog.
Z
X
Y
antepassado
antepassado
progenitor
Figura 2.4 Formulao recursiva da relao antepassado
H ainda uma questo importante a ser respondida: Como realmente o sistema Prolog utiliza o pro-
grama para encontrar as informaes procuradas? Uma explicao informal ser fornecida na prxima
seo, antes porm vamos reunir todas as partes do programa que foi sendo gradualmente ampliado
pela adio de novos fatos e regras. A forma final do programa mostrada na Figura 2.5. O programa
ali apresentado define diversas relaes: progenitor, masculino, feminino, antepassado, etc. A relao
antepassado, por exemplo, definida por meio de duas clusulas. Dizemos que cada uma delas so-
bre a relao antepassado. Algumas vezes pode ser conveniente considerar o conjunto completo de
clusulas sobre a mesma relao. Tal conjunto de clusulas denominado um predicado.
19
Na Figura 2.5, as duas regras sobre a relao antepassado foram distinguidas com os nomes [pr1] e
[pr2] que foram adicionados como comentrios ao programa. Tais nomes sero empregados adiante
como referncia a essas regras. Os comentrios que aparecem em um programa so normalmente ig-
norados pelo sistema Prolog, servindo apenas para melhorar a legibilidade do programa impresso. Os
comentrios se distinguem do resto do programa por se encontrarem includos entre os delimitadores
especiais "/*" e "*/". Um outro mtodo, mais conveniente para comentrios curtos, utiliza o caracter
de percentual "%": todo o texto informado entre o "%" e o final da linha interpretado como comen-
trio. Por exemplo:
/* Isto um comentrio. */
% E isto tambm.
progenitor(maria, jos). % Maria progenitor de Jos.
progenitor(joo, jos).
progenitor(joo, ana).
progenitor(jos, jlia).
progenitor(jos, ris).
progenitor(ris, jorge).
masculino(joo). % Joo do sexo masculino.
masculino(jos).
masculino(jorge).
feminino(maria). % Maria do sexo feminino.
feminino(ana).
feminino(jlia).
feminino(ris).
filho(Y, X) :- % Y filho de X se
progenitor(X,Y). % X progenitor de Y.
me(X,Y) :- % X me de Y se
progenitor(X, Y), % X progenitor de Y e
feminino(X). % X do sexo feminino.
av(X, Z) :- % X av de Z se
progenitor(X, Y), % X progenitor de Y e
progenitor(Y, Z). % Y progenitor de Z.
irm(X, Y) :- % X irm de Y se
progenitor(Z, X), % X tem um progenitor, Z que
progenitor(Z, Y), % tambm progenitor de Y e
feminino(X), % X do sexo feminino e
diferente(X, Y). % X e Y so diferentes.
antepassado(X, Z) :- % X antepassado de Z se
progenitor(X, Z). % X progenitor de Z. [pr1]
antepassado(X, Z) :- % X antepassado de Z se
progenitor(X, Y), % X progenitor de Y e
antepassado(Y, Z). % Y antepassado de Z. [pr2]
Figura 2.5 Um programa Prolog
2.4 CONSULTAS
Uma consulta em Prolog sempre uma seqncia composta por um ou mais objetivos. Para obter a
resposta, o sistema Prolog tenta satisfazer todos os objetivos que compem a consulta, interpretando-
os como uma conjuno. Satisfazer um objetivo significa demonstrar que esse objetivo verdadeiro,
assumindo que as relaes que o implicam so verdadeiras no contexto do programa. Se a questo
tambm contm variveis, o sistema Prolog dever encontrar ainda os objetos particulares que, atri-
budos s variveis, satisfazem a todos os sub-objetivos propostos na consulta. A particular instancia-
o das variveis com os objetos que tornam o objetivo verdadeiro ento apresentada ao usurio. Se
no for possvel encontrar, no contexto do programa, nenhuma instanciao comum de suas variveis
que permita derivar algum dos sub-objetivos propostos ento a resposta ser "no".
Uma viso apropriada da interpretao de um programa Prolog em termos matemticos a seguinte:
O sistema Prolog aceita os fatos e regras como um conjunto de axiomas e a consulta do usurio como
um teorema a ser provado. A tarefa do sistema demonstrar que o teorema pode ser provado com
base nos axiomas representados pelo conjunto das clusulas que constituem o programa. Essa viso
20
ser ilustrada com um exemplo clssico da lgica de Aristteles. Sejam os axiomas:
Todos os homens so falveis.
Scrates um homem.
Um teorema que deriva logicamente desses dois axiomas :
Scrates falvel
O primeiro axioma pode ser reescrito como: "Para todo X, se X um homem ento X falvel". Nessa
mesma linha o exemplo pode ser escrito em Prolog como se segue:
falvel(X) :-
homem(X).
homem(scrates).
?-falvel(X).
X=scrates
Um exemplo mais complexo, extrado do programa apresentada na Figura 2.5 :
?-antepassado(joo, ris).
Sabe-se que progenitor(jos, ris) um fato. Usando esse fato e a regra [pr1], podemos concluir ante-
passado(jos, ris). Este um fato derivado. No pode ser encontrado explcito no programa, mas
pode ser derivado a partir dos fatos e regras ali presentes. Um passo de inferncia como esse pode ser
escrito em uma forma mais complexa como:
progenitor(jos, ris) antepassado(jos, ris)
que pode ser lido assim: "de progenitor(jos, ris) segue, pela regra [pr1] que antepassado(jos,
ris)". Alm disso sabemos que progenitor(joo, jos) fato. Usando este fato e o fato derivado, ante-
passado(jos, ris), podemos concluir, pela regra [pr2], que o objetivo proposto, antepassado(joo,
ris) verdadeiro. O processo completo, formado por dois passos de inferncia, pode ser escrito:
progenitor(jos, ris) antepassado(jos, ris)
e
progenitor(joo, jos) e antepassado(jos, ris) antepassado(joo, ris)
Mostrou-se assim o que pode ser uma seqncia de passos de inferncia usada para satisfazer um ob-
jetivo. Tal seqncia denomina-se seqncia de prova. A extrao de uma seqncia de prova do
contexto formado por um programa e uma consulta obtida pelo sistema na ordem inversa da empre-
gada acima. Ao invs de iniciar a inferncia a partir dos fatos, o Prolog comea com os objetivos e ,
usando as regras, substitui os objetivos correntes por novos objetivos at que estes se tornem fatos.
Dada por exemplo a questo: "Joo antepassado de ris?", o sistema tenta encontrar uma clusula
no programa a partir da qual o oibjetivo seja conseqncia imediata. Obviamente, as nicas clusulas
relevantes para essa finalidade so [pr1] e [pr2], que so sobre a relao antepassado, porque so as
nicas cujas cabeas podem ser unificadas com o objetivo formulado. Tais clusulas representam dois
caminhos alternativos que o sistema pode seguir. Inicialmente o Prolog ir tentar a que aparece em
primeiro lugar no programa:
antepassado(X, Z) :- progenitor(X, Z).
uma vez que o objetivo antepassado(joo, ris), as variveis na regra devem ser instanciadas por
X=joo e Y=ris. O objetivo inicial, antepassado(joo, ris) ento substitudo por um novo objetivo:
progenitor(joo, ris)
No h, entretanto, nenhuma clusula no programa cuja cabea possa ser unificada com progeni-
tor(joo, ris), logo este objetivo falha. Ento o Prolog retorna ao objetivo original (backtracking)
para tentar um caminho alternativo que permita derivar o objetivo antepassado(joo, ris). A regra
[pr2] ento tentada:
antepassado(X, Z) :-
progenitor(X, Y),
21
antepassado(Y, Z).
Como anteriormente, as variveis X e Z so instanciadas para joo e ris, respectivamente. A varivel
Y, entretanto, no est instanciada ainda. O objetivo original, antepassado(joo, ris) ento substi-
tudo por dois novos objetivos derivados por meio da regra [pr2]:
progenitor(joo, Y), antepassado(Y, ris).
Encontrando-se agora face a dois objetivos, o sistema tenta satisfaz-los na ordem em que esto for-
mulados. O primeiro deles fcil: progenitor(joo, Y) pode ser unificado com dois fatos do programa:
progenitor(joo, jos) e progenitor(joo, ana). Mais uma vez, o caminho a ser tentado deve correspon-
der ordem em que os fatos esto escritos no programa. A varivel Y ento instanciada com jos
nos dois objetivos acima, ficando o primeiro deles imediatamente satisfeito. O objetivo remanescente
ento:
antepassado(jos, ris).
Para satisfazer tal objetivo, a regra [pr1] mais uma vez empregada. Essa segunda aplicao de [pr1],
entretanto, nada tem a ver com a sua utilizao anterior, isto , o sistema Prolog usa um novo conjunto
de variveis na regra cada vez que esta aplicada. Para indicar isso iremos renomear as variveis em
[pr1] nessa nova aplicao, da seguinte maneira:
antepassado(X', Z') :-
progenitor(X', Z').
A cabea da regra deve ento ser unificada como o nosso objetivo corrente, que antepassado(jos,
ris). A instanciao de X'e Y' fica: X'=jos e Y'=ris e o objetivo corrente substitudo por:
progenitor(jos, ris)
Esse objetivo imediatamente satisfeito, porque aparece no programa como um fato. O sistema en-
controu ento um caminho que lhe permite provar, no contexto oferecido pelo programa dado, o obje-
tivo originalmente formulado, e portanto responde "sim".
2.5 O SIGNIFICADO DOS PROGRAMAS PROLOG
Assume-se que um programa Prolog possua trs interpretaes semnticas bsicas. A saber: interpre-
tao declarativa, interpretao procedimental, e interpretao operacional.
Na interpretao declarativa entende-se que as clusulas que definem o programa descrevem uma
teoria de primeira ordem. Na interpretao procedimentas, as clusulas so vistas como entrada para
um mtodo de prova. Finalmente, na interpretao operacional as clusulas so vistas como comandos
para um procedimento particular de prova por refutao.
Tais alternativas semnticas so valiosas em termos de entendimento e codificao de programas
Prolog. A interpretao declarativa permite que o programador modele um dado problema atravs de
assertivas acerca dos objetos do universo de discurso, simplificando a tarefa de programao Prolog
em relao a outras linguagens tipicamente procedimentais como Pascal ou C. A interpretao proce-
dimental permite que o programador identifique e descreva o problema pela reduo do mesmo a sub-
problemas, atravs da definio de uma srie de chamadas a procedimentos. Por fim, a interpretao
operacional reintroduz a idia de controle da execuo (que irrelevante do ponto de vista da semn-
tica declarativa), atravs da ordenao das clusulas e dos objetivos dentro das clusulas em um pro-
grama Prolog. Essa tima interpretao semelhante semntica operacional de muitas linguagens
convencionais de programao, e deve ser considerada, principalmente em grandes programas, por
questes de eficincia. interessante notar que o programador pode comutar de uma interpretao
para outra, produzindo um efeito sinrgico que facilita consideravelmente a codificao dos progra-
mas Prolog.
22
Essa habilidade especfica do Prolog, de trabalhar em detalhes procedimentais de ao sobre o seu
prprio domnio de definio, isto , a capacidade de ser meta-programado, uma das principais
vantagens da linguagem. Ela encoraja o programador a considerar a semntica declarativa de seus
programas de modo relativamente independente dos seus significados procedimental e operacional.
Uma vez que os resultados do programa so considerados, em princpio, pelo seu significado declara-
tivo, isto deveria ser, por decorrncia, suficiente para a codificao de programas Prolog. Isso possui
grande importncia pratica, pois os aspectos declarativos do programa so em geral mais fceis de
entender do que os detalhes operacionais. Para tirar vantagem dessa caracterstica o programador deve
se concentrar principalmente no significado declarativo e , sempre que possvel, evitar os detalhes de
execuo. A abordagem declarativa, na realidade, torna a programao em Prolog mais fcil do que
nas linguagens convencionais. Infelizmente, entretanto, essa interpretao nem sempre suficiente.
Como dever ficar claro mais adiante, em problemas de maior complexidade os aspectos operacionais
no podem ser ignorados. Apesar de tudo, a atribuio de significado declarativo aos programas Pro-
log deve ser estimulada, na extenso limitada por suas restries de ordem prtica.
RESUMO
A programao em Prolog consiste em estabelecer relaes entre objetos e em formular con-
sultas sobre tais relaes.
Um programa Prolog formado por clusulas. H trs tipos de clusulas: fatos ou assertivas,
regras ou procedimentos e consultas;
Uma relao pode ser especificada por meio de fatos, que estabelecem as tuplas de objetos que
satisfazem a relao, por meio de regras, que estabelecem condies para a satisfao das rela-
es, ou por meio de combinaes de fatos e regras descrevendo a relao;
Denomina-se predicado ao conjunto de fatos e regras empregados para descrever uma determi-
nada relao;
Interrogar um programa acerca de suas relaes por meio de uma consulta corresponde a con-
sultar uma base de conhecimento. A resposta do sistema Prolog consiste em um conjunto de
objetos que satisfazem as condies originalmente estabelecidas pela consulta;
Em Prolog, estabelecer se um objeto satisfaz a uma consulta freqentemente um problema de
certa complexidade, que envolve inferncia lgica e a explorao de caminhos alternativos em
uma rvore de busca ou de pesquisa, com a possvel utilizao de mecanismos especiais de re-
torno (backtracking). Tudo isso feito automaticamente pelo sistema, de forma transparente ao
usurio;
Trs tipos de semntica so atribudas aos programas Prolog: declarativa, procedimental e ope-
racional. O programador deve empreg-las conforme o problema a ser resolvido, tirando pro-
veito da situao apresentada.
EXERCCIOS
2.1 Amplie o programa apresentado na Figura 2.5 para representar as relaes tio, prima, cunhado e
sogra.
2.2 Programe a relao descendente(X, Y), onde X descendente de Y.
2.3 Escreva um programa Prolog para representar o seguinte:
Joo nasceu em Pelotas e Jean nasceu em Paris.
Pelotas fica no Rio Grande do Sul.
Paris fica na Frana.
S gacho quem nasceu no Rio Grande do Sul.
23
2.4 Escreva um programa Prolog para representar o seguinte:
Os corpos celeste dignos de nota so as estrelas, os planetas e os cometas.
Vnus um corpo celeste, mas no uma estrela.
Os cometas possuem cauda quando esto perto do sol.
Vnus est perto do sol, mas no possui cauda.
2.5 Assuma que os arcos em um grafo expressem custos, como no exemplo abaixo:
A
B
C
D
E
F
3
5
4
2
4
5
2
2
e sejam descritos atravs de assertivas da forma
arco(R, S, T)
significando que h um arco de custo T entre os nodos R e S. Por exemplo, arco(A, B, 3) descre-
ve um arco de custo 3 entre os nodos A e B. Assuma tambm que o relacionamento mais(X, Y,
Z) vale quando X+Y=Z. Defina o relacionamento custo(U, V, L) de forma a expressar que existe
um caminho de custo L entre os nodos U e V.
24
3. SINTAXE E SEMNTICA
Prolog um nome comum para uma famlia de sistemas que implementam a lgica de predicados
como linguagem de programao. Algumas destas implementaes, como o Prolog de Edimburgo e o
IC-Prolog, so bastante conhecidas nos meios acadmicos. Outras, como o microProlog, o Quintus-
Prolog e o Arity Prolog ganharam popularidade em diferentes segmentos. No presente texto se adota,
visando maior clareza, uma sintaxe genrica, capaz de ser facilmente adaptada a qualquer ambiente
Prolog.
Objeto
Simples
Constante
Estrutura
tomo
Varivel
Nmero
Figura 3.1 Classificao dos Objetos Prolog
3.1 OBJETOS
Na Figura 3.1 apresenta-se uma classificao dos objetos em Prolog. O sistema reconhece o tipo de
um objeto no programa por meio de sua forma sinttica. Isso possvel porque a sintaxe do Prolog
especifica formas diferentes para cada tipo de objeto. Na sintaxe aqui adotada, comum maioria das
implementaes, variveis sempre iro iniciar com letras maisculas, enquanto que as constantes no-
numricas, ou tomos, iniciam com letras minsculas. Nenhuma informao adicional, tal como tipos
de dados precisa ser fornecida para que o sistema reconhea a informao com a qual est lidando.
3.1.1 TOMOS E NMEROS
No captulo anterior viu-se informalmente alguns exemplos simples de tomos e variveis. Em geral,
entretanto, estes podem assumir formas mais complexas. O alfabeto bsico adotado aqui para a lin-
guagem Prolog consiste dos seguintes smbolos:
Pontuao: ( ) . ' "
Conetivos: , (conjuno)
; (disjuno)
:- (implicao)
Letras: a, b, c, ..., z, A, B, C, ..., Z
Dgitos: 0, 1, 2, ..., 9
Especiais: + - * / < > = : _ ... etc.
25
Os tomos podem ser construdos de trs maneiras distintas:
a. Como cadeias de letras e/ou dgitos, podendo conter o caracter especial sublinhado (_), inician-
do obrigatoriamente com letra minscula. Por exemplo:
socrates x_y
nil mostraMenu
x47 a_b_1_2
b. Como cadeias de caracteres especiais. Por exemplo:
<--------> ::= =/= ======> .
.
. ++++
c. Como cadeias de caracteres quaisquer, podendo inclusive incluir espaos em branco, desde que
delimitados por apstrofos ('). Por exemplo:
'D. Pedro I'
'representao de conhecimento'
'13 de outubro de 1993'
'Robert Kowalski'
Um certo cuidado necessrio na formao de tomos do tipo (b.) porque algumas cadeias de caracte-
res especiais podem possuir um significado pr definido para o sistema Prolog subjacente, como cos-
tuma acontecer, por exemplo, com as cadeias '==' e '=\=' .
Os nmeros usados em Prolog compreendem os nmeros inteiros e os nmeros reais. A sintaxe dos
nmeros inteiros bastante simples, como pode ser visto nos exemplos abaixo:
1 1812 0 -273
Nem todos os nmeros inteiros podem ser representados em um computador, portanto o escopo de
variao dos nmeros inteiros est limitado a um intervalo entre algum menor e algum maior nmero,
dependendo da implementao. Normalmente a variao permitida nas implementaes correntes
suficiente para atender todas as necessidades do usurio.
O tratamento dos nmeros reais tambm varia de implementao para implementao. Ser adotada
aqui a sintaxe natural e consagrada, que faz uso do ponto decimal explcito.
3.14159 0.000023 -273.16
Os nmeros reais no so, na verdade, muito utilizados em programas Prolog tpicos. A razo disso
que o Prolog uma linguagem orientada ao processamento simblico, no-numrico, em oposio s
linguagens "devoradoras de nmeros", como por exemplo o Fortran. Na computao simblica, nme-
ros inteiros so frequentemente empregados, por exemplo, para contar os itens em uma lista, mas a
necessidade de nmeros reais bastante pequena, virtualmente inexistente.
3.1.2 VARIVEIS
Variveis Prolog so cadeias de letras, dgitos e do caracter sublinhado (_), devendo iniciar com este
ou com uma letra maiscula. O caracter "_", sozinho, representa uma varivel annima, isto , sem
interesse para um determinado procedimento. Exemplos de variveis so:
X
Resultado
Objeto2
Lista_de_Associados
_var35
_194
_ (varivel annima)
O escopo lxico de nomes de variveis apenas uma clusula. Isso quer dizer que, por exemplo, se o
nome X25 ocorre em duas clusulas diferentes, ento ele est representando duas variveis diferentes.
Por outro lado, toda ocorrncia de X25 dentro da mesma clusula quer significar a mesma varivel.
26
Essa situao diferente para as constantes: o mesmo tomo sempre significa o mesmo objeto ao
longo de todo o programa.
3.1.3 ESTRUTURAS
Objetos estruturados, ou simplesmente estruturas, so objetos que possuem vrios componentes. Os
prprios componentes podem, por sua vez, ser tambm estruturas. Por exemplo, uma data pode ser
vista como uma estrutura com trs componentes: dia, mes e ano. Mesmo que sejam formadas por di-
versos componentes as estruturas so tratadas no programa como objetos simples. Para combinar os
componentes em uma estrutura necessrio empregar um functor. Um functor um smbolo funcio-
nal (um nome de funo) que permite agrupar diversos objetos em um nico objeto estruturado. Um
functor adequada ao exemplo dado data, ento a data correspondente a 13 de outubro de 1993, cuja
estrutura est presente na Figura 3.2, pode ser escrita como:
data(13, outubro, 1993)
data
13 out. 1993
data
functor argumentos
(13, outubro, 1993)
(a) (b)
Figura 3.2 Uma data como exemplo de objeto estruturado
Na figura acima, em (a) temos a representao de data sob a forma de rvore e em (b) a forma como
escrita em Prolog. Todos os componentes no exemplo so constantes (dois inteiros e um tomo), en-
tretanto, podem tambm ser variveis ou outras estruturas. Um dia qualquer de maro de 1996, por
exemplo, pode ser representado por:
data(Dia, maro, 1996)
Note que "Dia" uma varivel e pode ser instanciada para qualquer objeto em algum ponto da execu-
o.
Sintaticamente todos os objetos em Prolog so denominados termos. O conjunto de termos Prolog, ou
simplesmente termos, o menor conjunto que satisfaz s seguintes condies:
Toda constante um termo;
Toda varivel um termo;
Se t1, t2, ..., tn so termos e f um tomo, ento f(t1, t2, ..., tn) tambm um termo, onde o
tomo f desempenha o papel de um smbolo funcional n-rio. Diz-se ainda que a expresso f(t1,
t2, ..., tn) um termo funcional Prolog.
Todos os objetos estruturados podem ser representados como rvores. A raiz da rvore o functor e
os ramos que dela partem so os argumentos ou componentes. Se algum dos componentes for tambm
uma rvore, ento ele passa a constituir uma sub-rvore do objeto estruturado completo. Por exemplo,
na Figura 3.3 mostrada a estrutura em rvore correspondente expresso:
(a + b) * (c - 5)
De acordo com a sintaxe dos termos Prolog, anteriormente apresentada, e tomando os smbolos "*",
"+" e "-" como functores, a expresso dada pode ser escrita:
*(+(a, b), -(c, 5))
27
*
+ -
a b c 5
Figura 3.3 Uma expresso aritmtica estruturada em rvore
Este , naturalmente, um termo legal em Prolog, entretanto, no a forma trivial com a qual estamos
acostumados. Normalmente se ir preferir a notao usual, infixa, como utilizada na matemtica. Na
verdade a linguagem Prolog admite as duas formas, prefixa e infixa, para a escrita de expresses arit-
mticas. Detalhes sobre operadores e definio de operadores especiais sero abordados mais adiante.
3.2 UNIFICAO
Na seo anterior foi visto como os objetos podem ser utilizados na representao de objetos de dados
complexos. A operao mais importante entre dois termos Prolog denominada unificao. A unifi-
cao pode, por si s, produzir alguns resultados interessantes. Dados dois termos, diz-se que eles
unificam se:
(1) Eles so idnticos, ou
(2) As variveis de ambos os termos podem ser instanciadas com objetos de maneira que, aps a
substituio das variveis por esses objetos, os termos se tornam idnticos.
Por exemplo, os termos data(D, M, 1994) e data(X, maro, A) unificam. Uma instanciao que torna
os dois termos idnticos :
D instanciada com X;
M instanciada com maro;
A instanciada com 1994.
Por outro lado, os termos data(D, M, 1994) e data(X, Y, 94) no unificam, assim como no unificam
data(X, Y, Z) e ponto(X, Y, Z). A unificao um processo que toma dois termos como entrada e
verifica se eles podem ser unificados. Se os termos no unificam, dizemos que o processo falha. Se
eles unificam, ento o processo bem-sucedido e as variveis dos termos que participam do processo
so instanciadas com os valores encontrados para os objetos, de modo que os dois termos participan-
tes se tornam idnticos. Vamos considerar novamente a unificao entre duas datas. O requisito para
que essa operao se efetue informada ao sistema Prolog pela seguinte consulta, usando o operador
"=":
?-data(D, M, 1994) = data(X, maro, A)
J foi mencionada a instanciao D=X, M=maro e A=1994, que obtm a unificao. H, entretanto,
outras instanciaes que tambm tornam os termos idnticos. Duas delas so:
D=1, X=1, M=maro, A=1994
D=terceiro, X=terceiro, M=maro, A=1994
Essas duas instanciaes so consideradas menos gerais do que a primeira, uma vez que restringem o
valor das variveis D e X mais fortemente do que seria necessrio.. Para tornar os dois termos do
exemplo idnticos, basta que D e X tenham o mesmo valor, seja qual for esse valor. A unificao em
Prolog sempre resulta na instanciao mais geral, isto , a que limita o mnimo possvel o escopo de
valores das variveis, deixando a maior liberdade possvel s instanciaes posteriores. As regras
28
gerais que determinam se dois termos S e T unificam so as seguintes:
Se S e T so constantes, ento S e T unificam somente se ambos representam o mesmo objeto;
Se S uma varivel e T qualquer coisa, ento S e T unificam com S instanciada com T. In-
versamente, se T uma varivel, ento T instanciada com S;
Se S e T so estruturas, unificam somente se: (1) S e T tem o mesmo functor principal, e (2) to-
dos os seus componentes correspondentes tambm unificam. A instanciao resultante deter-
minada pela unificao dos componentes.
Essa ltima regra pode ser exemplificada pelo processo de unificao dos termos
tringulo(ponto(1, 1), A, ponto(2, 3))
com
tringulo(X, ponto(4, Y), ponto(2, Z))
cuja representao em rvore apresentada na Figura 3.4.
tringulo
ponto A ponto
1 1 2 3
tringulo
ponto
2 Z
ponto
4 Y
X
Figura 3.4 Termos representados em rvore
O processo de unificao comea pela raiz (o functor principal). Como ambos os functores unificam,
o processo parte para a unificao dos argumentos, onde a unificao dos pares de argumentos corres-
pondentes ocorre. Assim o processo completo pode ser visto como a seguinte seqncia de operaes
de unificao simples:
tringulo = tringulo
ponto(1, 1) = X
A = ponto(4, Y)
ponto(2, 3) = ponto(2, Z)
O processo completo de unificao bem sucedido porque todas as unificaes na seqncia acima
tambm o so. A instanciao resultante :
X = ponto(1, 1)
A = ponto(4, Y)
Z = 3
3.3 SEMNTICA DECLARATIVA E SEMNTICA PROCEDIMENTAL
Conforme se estudou no captulo anterior, os programas Prolog podem ser interpretados de trs ma-
neiras distintas: declarativamente, procedimentalmente e operacionalmente. Iremos agora aprofundar
29
um pouco tais idias. Seja por exemplo a clusula:
P :- Q, R
onde P, Q e R possuem a sintaxe de termos Prolog. Duas alternativas para a leitura declarativa dessa
clusula so:
P verdadeira se Q e R so verdadeiras
e
De Q e R segue P
Por outro lado, duas leituras procedimentais alternativas so:
Para solucionar o problema P
primeiro solucione o subproblema Q
e depois solucione o subproblema R
Para satisfazer P, primeiro satisfaa Q e depois R
Assim a diferena entre as leituras declarativa e procedimental reside principalmente no fato que essa
ltima no apenas define o relacionamento lgico existente entre a cabea e o corpo da clusula,
como tambm exige a existncia de uma ordem na qual os objetivos sero processados.
A semntica declarativa dos programas determina se um dado objetivo verdadeiro e, se for, paera
que valores de variveis isto se verifica. Para definir precisamente o significado declarativo precisa-
mos introduzir o conceito de instncia de uma clusula. Uma instncia de uma clusula C essa
mesma clusula C com cada uma de suas variveis substituda por algum termo. Uma variante de uma
clusula C uma instncia dessa mesma clusula C com cada uma de suas variveis substituda por
outra varivel. Considere, por exemplo, a clusula:
temFilho(X) :- progenitor(X, Y).
Duas variantes dela so:
temFilho(A) :- progenitor(A, B).
temFilho(Joo) :- progenitor(Joo, Algum).
Duas instncias dela so:
temFilho(joo) :- progenitor(joo, Algum).
temFilho(sr(J)) :- progenitor(sr(J), jr(J)).
Assim, dado um programa e um objetivo G, o significado declarativo nos diz que:
"Um objetivo G verdadeiro (isto , satisfatvel ou segue logicamente do programa) se e somente se h uma clu-
sula C no programa e uma instncia I de C tal que: (1) A cabea de I idntica a G, e (2) todos os objetivos
no corpo de I so verdadeiros."
Essa definio pode ser estendida para as consultas como se segue: Em geral uma consulta ao sistema
Prolog uma lista de objetivos separados por vrgulas. Uma lista de objetivos verdadeira se todos os
objetivos nela contidos so verdadeiros para alguma instanciao de suas variveis. Os valores atri-
budos s variveis que tornam os objetivos da lista simultaneamente verdadeiros correspondem sua
instanciao mais geral.
Uma vrgula entre os objetivos significa a conjuno destes objetivos, isto , todos devem ser satis-
feitos. A linguagem Prolog tambm aceita a disjuno de objetivos: basta que um s dentre os objeti-
vos da disjuno seja satisfeito para que todo o conjunto seja considerado satisfeito. A operao de
disjuno representada pelo ponto-e-vrgula (;). Por exemplo, a clusula abaixo:
P :- Q; R.
lida: P verdadeiro se Q verdadeiro ou R verdadeiro. O significado da clusula portanto o
mesmo que:
P :- Q.
P :- R.
30
A operao de conjuno mais forte do que a disjuno, assim a clusula:
P :- Q, R; S, T, U.
deve ser entendida como:
P :- (Q, R); (S, T, U).
e significa o mesmo que as clusulas:
P :- Q, R.
P :- S, T, U.
3.4 SEMNTICA OPERACIONAL
O significado operacional especifica como o Prolog responde as consultas que lhe so formuladas.
Responder a uma consulta significa satisfazer uma lista de objetivos. Estes podem ser satisfeitos se as
variveis que neles ocorrem podem ser instanciadas de forma que eles possam ser conseqncia lgica
do programa. Assim, o significado operacional do Prolog o de um procedimento computacional para
executar uma lista de objetivos com respeito a um dado programa. Com executar objetivos se quer
significar tentar satisfaz-los. Considere o diagrama mostrado na Figura 3.5, representando tal proce-
dimento, que denominaremos executor. Suas entradas e sadas so: (1) entrada: um programa e uma
lista de objetivos; (2) sada: um indicador de sucesso/falha e instanciaes de variveis.
O significado dos resultados de sada do executor o seguinte:
O indicador de sucesso/falha tem o valor "sim" se os objetivos forem todos satisfeitos e "no"
em caso contrrio;
As instanciaes so produzidas somente no caso de concluso bem-sucedida e correspondem
aos valores das variveis que satisfazem os objetivos.
programa objetivos
executor
sucesso/falha instanciaes
Figura 3.5 Procedimento de execuo do sistema Prolog
RESUMO
At aqui estudou-se um tipo de Prolog bsico, denominado tambm de Prolog "puro". Esta denomina-
o devida ao fato de corresponder muito de perto lgica de predicados de primeira ordem. Exten-
ses cujo objetivo adequar a linguagem a necessidades prticas sero estudadas mais adiante. Os
pontos mais importantes do presente captulo so:
Objetos simples, em Prolog, so tomos, variveis e nmeros. Objetos estruturados, ou estrutu-
ras so empregados para representar entidades que possuem diversos componentes;
As estruturas so construdas por meio de functores. Cada functor definido por meio de seu
nome e sua aridade ou nmero de argumentos;
O tipo de um objeto reconhecido exclusivamente atravs de sua forma sinttica;
31
O escopo lxico das variveis em um programa uma clusula. O mesmo nome de varivel em
duas clusulas distintas representa duas variveis diferentes;
As estruturas Prolog podem ser sempre representadas por meio de rvores. Prolog pode ser
vista como uma linguagem orientada ao processamento de rvores;
A operao de unificao toma dois termos e tenta torn-los idnticos por meio da instanciao
das variveis em ambos;
Quando a unificao bem sucedida, resulta na instanciao mais geral das variveis envolvi-
das;
A semntica declarativa do Prolog define se um objetivo verdadeiro com relao a um dado
programa e, se for, para que particulares instanciaes de variveis isto ocorre;
Uma vrgula entre os objetivos significa a sua conjuno, enquanto que um ponto-e-vrgula si-
gnifica a sua disjuno;
A semntica operacional representa um procedimento para satisfazer a lista de objetivos no
contexto de um dado programa. A sada desse procedimento o valor-verdade da lista de obje-
tivos com a respectiva instanciao de sua variveis. O procedimento permite o retorno auto-
mtico (backtracking) para o exame de novas alternativas;
A interpretao declarativa de programas escritos em Prolog puro no depende da ordem das
clusulas nem da ordem dos objetivos dentro das clusulas;
A interpretao procedimental depende da ordem dos objetivos e clusulas. Assim a ordem
pode afetar a eficincia de um programa. Uma ordenao inadequada pode mesmo conduzir a
chamadas recursivas infinitas;
EXERCCIOS
3.1 Quais dos seguintes objetos esto sintaticamente corretos e a que tipo de objeto pertencem?
a. Daniela
b. daniela
c. 'Daniela'
d. _daniela
e. 'Daniela vai a Paris'
f. vai(daniela, paris)
g. 8118
h. 2(X, Y)
i. +(sul, oeste)
j. trs(Cavalos(Baios))
3.2 Sugira uma representao para retngulos, quadrados, crculos e elipses, usando uma abordagem
similar apresentada na Figura 3.4. Procure obter a representao mais geral possvel, por exem-
plo, um quadrado um caso especial de retngulo e um crculo pode ser considerado um caso es-
pecial de elipse.
3.3 Quais das prximas operaes de unificao sero bem sucedidas e quais iro falhar? Para as que
forem bem sucedidas, quais so as instanciaes de variveis resultantes?
a. ponto(A, B) = ponto(1, 2)
b. ponto(A, B) = ponto(X, Y, Z)
c. mais(2, 2) = 4
d. +(2, D) = +(E, 2)
e. t(p(-1,0), P2, P3) = t(P1, p(1, 0), p(0, Y))
3.4 Defina uma representao Prolog para segmentos de reta no plano expressos em funo dos
32
pontos limites. Que termo ir representar qualquer segmento de reta vertical em X=5?
3.5 Supondo que um retngulo seja representado pelo termo:
retngulo(SupEsq, InfDir)
onde SupEsq representa o ponto superior esquerdo e InfDir o ponto inferior direito de um retn-
gulo em uma tela de vdeo (1280 x 1024), defina a relao
quadrado(R, ...)
que verdadeira se R um quadrado.
3.6 Considere o seguinte programa:
f(1, um).
f(s(1), dois).
f(s(s(1))), trs).
f(s(s(s(X))), N) :- f(X, N).
Como iria o sistema Prolog responder as seguintes questes? Quando vrias respostas so poss-
veis, d pelo menos duas:
a. ?-f(s(1), A).
b. ?-f(s(s(1)), dois).
c. ?-f(s(s(s(s(s(s(1)))))), C).
d. ?-f(D, trs).
33
4. OPERADORES E ARITMTICA
4.1 OPERADORES
Na matemtica costuma-se escrever expresses como
2*a + b*c
onde + e * so operadores e 2, a, b e c so argumentos. Em particular, + e * so denominados opera-
dores infixos porque se localizam entre os dois argumentos que operam. Tais expresses so repre-
sentadas por rvores como na Figura 4.1 e podem ser escritas, se for desejado, sob a forma de termos
Prolog, com os smbolos + e * como functores:
+(*(2, a), *(b, c))
+
* *
2 a b c
Figura 4.1 Representao em rvore da expresso +(*(2, a), *(b, c))
Normalmente, entretanto, prefervel escrever as expresses matemticas na forma usual, com os
operadores infixos, como em:
2*a + b*c
Tal notao tambm aceita pelo Prolog, entretanto, trata-se apenas da representao externa deste
objeto, que ser automaticamente convertida para a forma convencional dos termos Prolog. Na sada,
entretanto, o termo ser novamente convertido para a forma externa, com os operadores infixos.
Assim, as expresses matemticas so manipuladas pelo Prolog como meras extenses notacionais e
nenhum novo princpio para a estruturao de objetos est sendo proposto. Se for escrito a+b, o sis-
tema ir reconhecer e manipular tal expresso exatamente como se houvesse sido escrito +(a, b). Para
que o sistema entenda apropriadamente expresses tais como a+b*c, necessrio existir uma priori-
dade de execuo entre os operadores. Assim o operador + executado prioritariamente ao operador
*. essa prioridade de execuo que decide qual a interpretao correta da expresso. Por exemplo, a
expresso a+b*c poderia em princpio ser entendida como:
+(a, *(b, c)) ou *(+(a, b), c)
A regra geral que o operador de maior prioridade seja o functor principal do termo. Se expresses
contendo + e * devem ser entendidas segundo as convenes usuais, ento + deve ter maior precedn-
cia que *. Assim a expresso a+b*c deve ser entendida como a+(b*c). Se outra interpretao preten-
dida, deve ser indicada explicitamente com o uso de parnteses, como em (a+b)*c.
O programador Prolog pode tambm definir os seus prprios operadores, isto , definir tomos tais
como tem e suporta como se fossem operadores infixos e ento escrever no programa fatos como:
pedro tem informaes
assoalho suporta mesa
que so exatamente equivalentes a
34
tem(pedro, informaes)
suporta(assoalho, mesa)
A definio de novos operadores realizada pela insero no programa de um certo tipo especial de
clusulas, denominadas diretivas, que atuam como definidoras de operadores. Uma expresso defini-
dora de um operador deve aparecer no programa antes de qualquer expresso que contenha esse ope-
rador. Por exemplo, o operador tem pode ser definido pela diretiva:
:- op(600, xfx, tem).
Isso informa ao sistema que se deseja usar tem como um operador de prioridade 600 e cujo tipo
"xfx", que designa uma classe de operadores infixos. A forma de especificao, "xfx", sugere que o
operador, denotado por "f", deva ser colocado entre dois argumentos, denotados por "x".
Deve-se notar que as definies de operadores no especificam qualquer operao ou ao. Em prin-
cpio, nenhuma operao sobre objetos associada definio de operadores. Os operadores so
normalmente empregados como functores, isto , somente para combinar objetos em estruturas e no
para executar alteraes sobre tais objetos, apesar do termo "operador" sugerir essa execuo. Os
nomes dos operadores so tomos e sua prioridade encontra-se delimitada por valores inteiros cujo
intervalo depende da implementao. Assumiremos aqui que esse intervalo varie entre 1 e 1200. H
trs tipos bsicos de operadores, conforme a tabela abaixo:
Tabela 4.1 Tipos de Operadores Prolog
OPERADORES TIPO
Infixos xfx xfy yfx
Prefixos fx fy -
Posfixos xf yf -
A notao dos especificadores de tipo foi projetada para refletir a estrutura da expresso, onde f re-
presenta o operador e x e y representam os argumentos. Um f aparecendo entre os argumentos indica
que o operador infixo. As formas prefixo e posfixo possuem apenas um argumento que segue ou
precede o operador respectivamente.
H uma diferena entre x e y. Para explic-la necessrio introduzir a noo de prioridade de argu-
mento. Se um argumento estiver entre parnteses, ou for um objeto simples, ento sua prioridade
zero. Se um argumento uma estrutura, ento sua prioridade igual prioridade de seu functor prin-
cipal. O x representa um argumento cuja prioridade obrigatoriamente menor do que a do operador,
enquanto que y representa um argumento cuja prioridade menor ou igual prioridade do operador.
Essas regras auxiliam a evitar ambigidades em expresses com muitos operadores de mesma priori-
dade. Por exemplo, a expresso:
a - b - c
normalmente entendida como (a-b)-c e no como a-(b-c). Para atingir a interpretao usual, o opera-
dor "-" tem que ser definido como yfx. A Figura 4.2 mostra como isso ocorre.
Na figura 4.2, assumindo que "-" tem a prioridade 500, se "-" for do tipo yfx, ento a interpretao (b)
invlida, porque a precedncia de (b-c) tem de ser obrigatoriamente menor do que a precedncia de
"-". Como ou outro exemplo, considere o operador prefixo not. Se not for definido como fy, ento a
expresso
not not p
vlida. Por outro lado, se not for definido como fx a expresso ilegal, porque o argumento do pri-
meiro not not p, que tem a mesma prioridade que o not. Neste ltimo caso a expresso precisa ser
escrita entre parnteses:
not(not p)
35
- -
(a-b) (b-c)
c a
prioridade 500 prioridade 500
prioridade zero
(a) (b)
Figura 4.2 Duas interpretaes para a expresso a - b - c
Para a convenincia do programador, alguns operadores so pr-definidos no sistema Prolog, de forma
que esto sempre disponveis para utilizao, sem que seja necessrio defini-los. O que esses operado-
res fazem e quais so as suas prioridades ir depender de cada particular implementao. Adotaremos
aqui um conjunto padro de operadores, conforme as definies apresentadas na Figura 4.3. Como
tambm mostrado ali, diversos operadores podem ser definidos em uma nica diretiva, se eles tem
todos a mesma prioridade e so todos do mesmo tipo. Neste caso os nomes dos operadores so escri-
tos como uma lista delimitada por colchetes.
:- op(1200, xfx, ':-').
:- op(1200, fx [':-', '?-']).
:- op(1100, xfy, ';').
:- op(1000, xfy, ',').
:- op( 700, xfx, [is, =, <, >, =<, >=, ==, =\=, \==, =:=]).
:- op( 500, yfx, [+, -]).
:- op( 500, fx, [+, -, not]).
:- op( 400, yfx, [*,/,div]).
:- op( 300, xfx, mod).
:- op( 200, xfy, ^).
Figura 4.3 Um conjunto padro de operadores pr-definidos
O uso de operadores pode melhorar muito a legibilidade de alguns programas. Como um exemplo,
vamos assumir que estejamos escrevendo um programa para a manipulao de expresses booleanas e
que em tal programa desejamos estabelecer uma das leis de equivalncia de De Morgan:
(A B) <===> A B
que pode ser estabelecida em Prolog pela clusula:
equivale(no(e(A, B)), ou(no(A), no(B))).
Entretanto uma boa prtica em programao Prolog tentar reter a maior semelhana possvel entre a
notao original do problema e a notao usada noi programa. Em nosso exemplo isso pode ser obtido
por meio do uso de operadores. Um conjunto adequado de operadores para o nosso propsito pode ser
definido como:
:- op( 800, xfx, <===> ).
:- op( 700, xfy, ).
:- op( 600, xfy, ).
:- op( 500, fy, ).
com os quais a lei de De Morgan pode ser escrita como o fato:
(A B) <===> A B.
que, conforme estabelecido anteriormente, pode ser entendido como mostrado na figura abaixo:
36
<===>


A B A B
Figura 4.4 Interpretao do termo (A B) <===> A B
4.2 ARITMTICA
A linguagem Prolog principalmente utilizada - como j se viu - para a computao simblica, onde
as necessidades de clculo so comparativamente modestas. Assim, o instrumental da linguagem
Prolog destinado a computaes numricas algo simples em comparao com outras linguagens
destinadas especificamente para esse fim, como por exemplo o Pascal-SC. Alguns dos operadores pr-
definidos, anteriormente vistos podem ser usados para computao numrica. Tais operadores so
mostrados na Tabela 4.2.
Tais operadores, excepcionalmente, executam uma certa operao. Mesmo em tais casos, entretanto,
necessrio introduzir uma indicao adicional para executar a ao necessria. O sistema sabe como
conduzir a operao denotada pelos operadores, entretanto isso no suficiente para conduzir a se-
qncia da ao.
Tabela 4.2 Operadores pr-definidos para computao numrica
OPERADOR PRIORIDADE TIPO SIGNIFICADO
+ 500 yfx adio
- 500 yfx subtrao
* 400 yfx multiplicao
/ 400 yfx diviso
div 400 yfx diviso inteira
mod 300 xfx resto da diviso inteira
^ 200 xfy potenciao
A consulta mostrada a seguir, assim como a resposta obtida, representam uma tentativa ingnua de
obter computao numrica:
?-X = 1 + 2.
X = 1 + 2
e no X = 3 como se poderia esperar. A razo simples: a expresso "1 + 2" denota simplesmente um
termo Prolog, onde + o functor e 1 e 2 so os argumentos. No h nada no termo acima que efetiva-
mente obrigue o Prolog a ativar a operao de adio. Um operador pr-definido especial "is" forne-
cido para ordenar a execuo da operao representada, forando as computaes numricas envolvi-
das. A maneira correta de se obter o resultado da adio proposta acima :
?-X is 1 + 2.
X = 3
A adio aqui executada por um procedimento especial associado ao operador "is". Tais procedi-
mentos so denominados procedimentos embutidos. No h concordncia geral sobre notao aritm-
tica em Prolog, de forma que diferentes implementaes da linguagem podem utilizar notaes algo
diferentes. Por exemplo, o operador "/" pode denotar diviso inteira ou diviso em ponto flutuante,
37
dependendo da implementao. Aqui, "/" denotar a diviso em ponto flutuante, enquanto que o ope-
rador "div" denotar a diviso inteira. Exemplificando, na consulta abaixo:
?-X is 3/2, Y is 3 div 2.
X=1.5 Y=1
O argumento esquerda do operador "is" deve ser um objeto simples. O argumento direita deve ser
uma expresso aritmtica, composta de operadores aritmticos, variveis e nmeros. Uma vez que o
operador "is" ir forar a execuo da operao indicada, todas as variveis contidas na expresso
devem estar instanciadas com nmeros no momento da execuo de tal objetivo. A prioridade dos
operadores aritmticos pr-definidos (ver Figura 4.4) tal que a associatividade dos argumentos com
os operadores a mesma normalmente usada em matemtica. Os parnteses podem ser usados para
indicar associaes diferentes. Note que +, -, *, / e div so definidos como yfx, o que significa que a
execuo se dar da esquerda para a direita. Por exemplo, X is 5-2-1 interpretado como X is (5-2)-1.
A aritmtica tambm envolvida na comparao de valores numricos. Por exemplo, a verificao se
o produto de 277 por 37 maior que 10000 pode ser especificada pelo objetivo:
?-277 * 37 > 10000.
sim
Note que de forma semelhante ao operador "is", o operador ">" tambm fora a avaliao de expres-
ses. Suponha-se, por exemplo, uma relao denominada "nasceu", que relaciona nomes de pessoas
com seus respectivos anos de nascimento. Ento possvel recuperar os nomes das pessoas nascidas
entre 1970 e 1980 inclusive, com a seguinte questo:
?-nasceu(Nome, Ano),
Ano >= 1970,
Ano =< 1980.
Na tabela abaixo apresenta-se um conjunto padro de operadores de comparao utilizados em Pro-
log:
Tabela 4.3 Operadores de Comparao
OPERADOR PRIORIDADE TIPO SIGNIFICADO
> 700 xfx maior que
< 700 xfx menor que
>= 700 xfx maior ou igual a
=< 700 xfx menor ou igual a
=:= 700 xfx valores iguais
=\= 700 xfx valores diferentes
Note que a diferena existente entre o operador de unificao e o operador =:=, por exemplo, nos
objetivos X = Y e X =:= Y. O primeiro objetivo ir ocasionar a unificao dos objetos X e Y, instan-
ciando, se for o caso, alguma varivel em X e Y. Por outro lado, X =:= Y ocasiona a avaliao arit-
mtica sem causar a instanciao de nenhuma varivel. As diferenas se tornam claras nos exemplos a
seguir:
?-1+2 =:= 2+1.
sim
?-1+2 = 2+1.
no
?-1+A = B+2.
A=2 B=1
Mesmo no sendo direcionadas para a computao aritmtica, as diferentes implementaes do Prolog
normalmente possuem um conjunto de funes pr-definidas para a execuo de clculos cientficos.
Tais funes podem ser empregadas em expresses matemticas de modo similar s linguagens con-
vencionais. Um conjunto padro de tais funes apresentado na tabela abaixo:
Tabela 4.4 Funes Pr-Definidas em Prolog
38
FUNO SIGNIFICADO
abs(X) Valor absoluto de X
acos(X) Arco-cosseno de X
asin(X) Arco-seno de X
atan(X) Arco-tangente de X
cos(X) Cosseno de X
exp(X) Valor de "e" elevado a X
ln(X) Logaritmo natural de X
log(X) Logaritmo decimal de X
sin(X) Seno de X
sqrt(X) Raiz quadrada de X
tan(X) Tangente de X
round(X,N) Arredonda X para N casas decimais
Pi Valor de p com 15 casas decimais
Random Um nmero aleatrio entre 0 e 1
Por exemplo, so vlidas as seguintes expresses Prolog:
X is 3 * (cos(random))^2.
Y is sin(pi/6)*sqrt(tan(pi/12)).
Como um exemplo mais complexo, suponha o problema de computar o mximo divisor comum de
dois nmeros. Dados dois inteiros positivos, X e Y, seu mximo divisor comum D pode ser encontra-
do segundo trs casos distintos:
(1) Se X e Y so iguais, ento D igual a X;
(2) Se X<Y, ento D igual ao mdc entre X e a diferena X-Y;
(3) Se X>Y, ento cai-se no mesmo caso (2), com X substitudo por Y e vice-versa.
As trs clusulas Prolog que que expressam os trs casos acima so:
mdc(X, X, X).
mdc(X, Y, D) :-
X < Y,
Y1 is Y-X,
mdc(X, Y1, D).
mdc(X, Y, D) :-
X > Y,
mdc(Y, X, D).
Naturalmente, o ltimo objetivo na terceira clusula poderia ser de modo equivalente substitudo por:
X1 is X-Y,
mdc(X1, Y, D).
Um ltimo exemplo ser dado para recursivamente calcular o fatorial de um nmero inteiro dado. O
programa :
fatorial(0, 1).
fatorial(X, Y) :-
X1 is X-1,
fatorial(X1, Y1),
Y is X*Y1.
interessante notar aqui que o processo recursivo mantm latentes todas as operaes aritmticas at
que o fato "fatorial(0, 1)" seja alcanado, quando ento, todas as operaes pendentes so executadas
para fornecer em Y o fatorial desejado.
RESUMO
A notao para definio de operadores permite ao programador adequar a sintaxe de seus pro-
gramas para suas necessidades particulares, melhorando consideravelmente sua legibilidade;
39
Novos operadores so definidos por meio da diretiva "op", que estabelece o nome do operador,
seu tipo e prioridade;
Em princpio no h nenhuma execuo associada a um operador, que so meramente dispositi-
vos sintticos que oferecem a possibilidade de se escrever termos Prolog em uma sintaxe alter-
nativa;
A aritmtica executada por meio de procedimentos embutidos. A aaliaao de uma expressao aritmtica or-
ada pelo uso do operador "is" e dos operadores de comparaao. No momento da aaliaao, todas as ariaeis
deem estar instanciadas.
EXERCCIOS
4.1 Assumindo as seguintes definies de operadores:
:- op(300, xfx, joga).
:- op(200, xfy, e).
ento os dois termos seguintes possuem sintaxe vlida:
T1 = marcelo joga futebol e squash.
T2 = renata joga tenis e basquete e volei.
Como estes termos so interpretados pelo Prolog? Qual o functor principal de cada termo e
qual a sua estrutura?
4.2 Sugira uma apropriada definio dos operadores "era" e "do" para que seja possvel a escrita de
clusulas como:
vera era secretria do departamento.
e
paulo era professor do curso.
4.3 Considere o seguinte programa Prolog:
t(0+1, 1+0).
t(X+0+1, X+1+0).
t(X+1+1, Z) :-
t(X+1, X1),
t(X1+1, Z).
Como ir este programa responder as seguintes questes, considerando ser + um operador infixo
do tipo yfx (como usual).
a. ?-t(0+1, A).
b. ?-t(0+1+1, B).
c. ?-t(1+0+1+1+1, C).
d. ?-t(D, 1+1+1+0).
4.4 Defina os operadores "se", "ento", "seno" e ":=" de modo que seja vlido o termo:
se X>Y ento Z := X seno Z := Y
Escolha a precedncia dos operadores de modo que "se" venha a ser o functor principal. Depois
defina a relao "se" como um mini-interpretador para um tipo de comando se-ento da forma:
se V1>V2 ento Var:=V3 seno Var:=V4
onde V1, V2, V3 e V4 so nmeros (ou variveis instanciadas com nmeros) e Var uma vari-
vel. O significado da relao "se" deve ser: "se o valor de V1 maior que o valor de V2, ento
Var instanciada com V3, seno Var instanciada com V4. Um exemplo do uso do mini-
interpretador seria:
?-X=2, Y=3, V2 is 2*X, V4 is 4*X,
se Y > V2 ento Z:=Y seno Z:=V4,
se Z > 5 ento W=1 seno W=0.
X=2 Y=3 Z=8 W=1
4.5 Defina o procedimento
40
entre(N1, N2, X)
que, para dois inteiros dados, N1 e N2, produz atravs de backtracking todos os inteiros X que
satisfazem a restrio
N1 X N2
4.6 Estude a definio de um "mundo de polgonos" onde os objetos so definidos em funo das
coordenadas de seus vrtices no plano. Indivduos desse universo seriam tringulos, retngulos,
quadrados, etc. Por exemplo o termo:
tringulo((1,1), (1,2), (2,2))
definiria um tringulo cujos vrtices seriam os pontos (1,1), (1,2) e (2, 2) em um sistema de co-
ordenadas cartesianas.
Formule as propriedades bsicas de cada objeto atravs de relaes unrias, tais como:
issceles(X)
Formule relaes entre diferentes indivduos, representando assertivas tais como:
"Uma casa um quadrado com um tringulo em cima".
ou
"D distncia entre os centros geomtricos de A e B".
Pense numa verso deste programa para gerar trajetrias de figuras planas ao longo de curvas de
equaes dadas.
41
5. PROCESSAMENTO DE LISTAS
Uma importante classe de estruturas de dados em Prolog composta de expresses simblicas, tam-
bm denominadas "S-Expresses", que permitem a representao de listas de tamanho indefinido
como tipos de rvores onde os ramos, tambm denominados sub-rvores, so reunidos entre parnte-
ses e outros delimitadores para formar sequncias de objetos. A analogia entre listas aninhadas e rvo-
res fundamental para o perfeito entendimento de algumas operaes realizadas em listas. A sintaxe
das listas em Prolog uma variante da sintaxe empregada em LISP, que uma linguagem tradicio-
nalmente empregada em inteligncia artificial e computao simblica. No presente captulo aborda-
se a representao em listas, a codificao em Prolog de diversas operaes e a construo de algumas
aplicaes empregando estruturas em listas.
5.1 REPRESENTAO DE LISTAS
Listas so estruturas simples de dados, largamente empregadas em computao no-numrica. Uma
lista uma seqncia de qualquer nmero de itens, como: brasil, uruguai, argentina, paraguai. Uma
lista deste tipo pode ser escrita em Prolog como:
[brasil, uruguai, argentina, paraguai]
Essa, entretanto, apenas a aparncia externa das listas. Como j foi visto, todos os objetos estrutura-
dos em Prolog so na realidade rvores e as listas seguem a regra. Como representar listas como ob-
jetos Prolog? Dois casos devem ser considerados: a lista vazia e a lista no-vazia. No primeiro caso, a
lista representada simplesmente como um tomo, []. No segundo, a lista deve ser pensada como
constituda de dois componentes: uma "cabea" e um "corpo". Por exemplo, na lista dada, a cabea
"brasil" e o corpo a lista [uruguai, argentina, paraguai].
Em geral, a cabea pode ser qualquer objeto Prolog - como uma rvore ou uma varivel. O corpo,
entretanto, deve ser obrigatoriamente uma lista. A cabea e o corpo so combinados em uma estrutura
por meio de um functor especial. A escolha desse functor depende da implementao considerada da
linguagem Prolog. Aqui ser assumido o ponto "" que o smbolo funcional adotado com maior
freqncia na representao de listas nas diversas implementaes Prolog:
(Cabea, Corpo)
Uma vez que a varivel Corpo representa, por sua vez, uma lista, esta pode ser vazia ou possuir a sua
prpria cabea e corpo, portanto, para a representao de listas de qualquer tamanho, nenhum princ-
pio adicional necessrio. O exemplo de lista dado ento representado pelo termo Prolog:
(brasil, (uruguai, (argentina, (paraguai, [])))).




brasil
uruguai
argentina
paraguai
[]
Figura 5.1 Uma lista representada como rvore.
Na Figura 5.1 apresenta-se a correspondente estrutura em rvore. Note que a lista vazia aparece no
termo acima. Isso ocorre porque o ltimo "corpo" uma lista de um nico item [paraguai], que possui
uma lista vazia como seu corpo:
42
[paraguai] = (paraguai, [])
Esse exemplo mostra como o princpio geral para a estruturao de objetos Prolog tambm se aplica a
listas de qualquer tamanho. Como o exemplo tambm mostra, a notao direta com o uso do functor "
" pode produzir expresses bastante confusas. Por essa razo o sistema Prolog oferece uma notao
simplificada para as listas, permitindo que as mesmas sejam escritas como seqncias de itens separa-
dos por vrgulas e includos entre colchetes. O programador pode empregar qualquer notao, entre-
tanto, a que utiliza colchetes normalmente preferida. Segundo tal notao, um termo da forma [H|T]
tratado como uma lista de cabea H e corpo T. Listas do tipo [H|T] so estruturas muito comuns em
programao no-numrica. Deve-se recordar que o corpo de uma lista sempre outra lista, mesmo
que seja vazia. Os seguintes exemplos devem servir para demonstrar tais idias:
[X | Y] ou [X | [Y | Z]] unificam com [a, b, c, d]
[X, Y, Z] no unifica com [a, b, c, d]
[a, b, c] == [a | [b | [c]]] == [a | [b, c]] == [a, b | [c]] == [a, b, c | []]
As consultas abaixo tambm so elucidativas:
?-[X | Y] = [a, b, c].
X=a Y=[b, c]
?-[X, Y, Z] = [a, b, c, d].
no
?-[X | [Y | Z]] = [a, b, c, d].
X=a Y=b Z=[c, d]
5.2 OPERAES SOBRE LISTAS
Estruturas em lista podem ser definidas e transformadas em Prolog de diversas maneiras diferentes.
Na presente seo procura-se, atravs de uma variedade de exemplos, mostrar a flexibilidade das lis-
tas na representao de situaes complexas. Emprega-se, para maior clareza, de agora em diante a
notao:
simbolo_predicativo/aridade
para a identificao de predicados. Por exemplo grfico/3 denota uma relao denominada grfico
com trs argumentos. Esse detalhamento s vezes importante. Nome e aridade so os elementos
necessrios e suficientes para a perfeita identificao de um predicado.
5.2.1 CONSTRUO DE LISTAS
A primeira necessidade para a manipulao de listas ser capaz de constru-las a partir de seus ele-
mentos bsicos: uma cabea e um corpo. Tal relao pode ser escrita em um nico fato:
cons(X, Y, [X | Y]).
Por exemplo:
?-cons(a, b, Z).
Z=[a | b]
Durante a unificao a varivel X instanciada com a, Y com b e Z com [X|Y], que por sua vez
instanciada com [a|b], devido aos valores de X e Y. Se X for um elemento e Y uma lista, ento [X|Y]
uma nova lista com X como primeiro elemento. Por exemplo:
?-cons(a, [b, c], Z).
Z=[a, b, c]
?-cons(a, [], Z).
Z=[a]
A generalidade da unificao permite a definio de um resultado implcito:
43
?-cons(a, X, [a, b, c]).
X=[b, c]
Neste ltimo exemplo as propriedades de simetria dos argumentos, lembram um solucionador de
equaes: um X encontrado tal que [a|X] = [a, b, c]. Entretanto, se o primeiro argumento for uma
lista com, digamos, trs elementos e o segundo uma lista com dois, o resultado no ser uma lista com
cinco elementos:
?-cons([a, b, c], [d, e], Z).
Z=[[a, b, c], d, e]
de modo que o predicado cons/3 no resolve o problema de concatenar duas listas em uma terceira.
Mais adiante ser estudado o predicado conc/3 que realiza tal funo.
5.2.2 OCORRNCIA DE ELEMENTOS EM UMA LISTA
Vamos implementar um tipo de relao de ocorrncia que estabelece se determinado objeto membro
de uma lista, como em:
membro(X, L)
onde X um objeto e L uma lista. O objetivo membro(X, L) verdadeiro se X ocorre em L. Por
exemplo, so verdadeiros:
membro(b, [a, b, c])
membro([b,c], [a, [b, c], d])
mas a declarao
membro(b, [a, [b, c]])
falsa. O programa que define a relao membro/2 baseia-se na seguinte afirmao:
X membro de L se
(1) X a cabea de L, ou
(2) X membro do corpo de L.
que pode ser representada em Prolog por meio de duas clusulas. A primeira, um fato, estabelece a
primeira condio: X membro de L, se X a cabea de L. A segunda, uma regra que ser empregada
quando X no cabea de L, uma chamada recursiva que diz que X ainda pode ser membro de L,
desde que seja membro do corpo de L. Em Prolog:
membro(X, [X | C]).
membro(X, [Y | C]) :-
membro(X, C).
Note-se que o corpo da lista na primeira clusula sempre um resultado sem qualquer interesse, o
mesmo ocorrendo com a cabea da lista na segunda. possvel ento empregar variveis annimas e
escrever o predicado de forma mais elegante:
membro(X, [X | _]).
membro(X, [_ | C]) :-
membro(X, C).
5.2.3 CONCATENAO DE LISTAS
Para a concatenao de duas listas quaisquer, resultando em uma terceira, se definir a relao:
conc(L1, L3, L3)
onde L1 e L2 so duas listas e L3 a concatenao resultante. Por exemplo:
conc([a, b], [c, d], [a, b, c, d])
Novamente, dois casos devem ser considerados para a definio de conc/3, dependendo do primeiro
argumento L1:
(1) Se o primeiro argumento uma lista vazia, ento o segundo e o terceiro argumentos devem ser
44
a mesma lista. Chamando tal lista de L, essa situao pode ser representada pelo seguinte fato
Prolog:
conc([], L, L).
(2) Se o primeiro argumento de conc/3 for uma lista no-vazia, ento porque ela possui uma ca-
bea e um corpo e pode ser denotada por [X|L1]. A concatenao de [X|L1] com uma segunda
lista L2, produzir uma terceira lista com a mesma cabea X da primeira e um corpo L3 que a
concatenao do corpo da primeira lista, L1, com toda a segunda, L2. Isso pode ser visto na fi-
gura 5.2, e se representa em Prolog por meio da regra:
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
L1 L2 X
X L3
Figura 5.2 Concatenao de duas listas
O programa completo para a concatenao de listas, descrevendo o predicado conc/3 apresentado a
seguir:
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
Exemplos simples de utilizao de tal programa so:
?-conc([a, b, c], [1, 2, 3], L).
L=[a, b, c, 1, 2, 3]
?-conc([a, [b, c], d], [a, [], b], L).
L=[a, [b, c], d, a, [], b]
?-conc([a, b], [c | R], L).
L=[a, b, c | R]
O programa conc/3, apesar de muito simples, tambm muito flexvel e pode ser usado em inmeras
aplicaes. Por exemplo, ele pode ser usado no sentido inverso ao que foi originalmente projetado
para decompor uma lista em duas partes:
?- conc(L1, L2, [a, b, c]).
L1=[] L2=[a, b, c];
L1=[a] L2=[b, c];
L1=[a, b] l2=[c];
L1=[a, b, c] L2=[];
no
Esse resultado mostra que sempre possvel decompor uma lista de n elementos em n+1 modos, todos
eles obtidos pelo programa atravs de backtracking. Podemos tambm usar o programa para procurar
por um determinado padro em uma lista. Por exemplo, podemos encontrar os meses antes e depois de
um determinado mes:
?-M=[jan,fev,mar,abr,mai,jun,jul,ago,set,out,nov,dez], conc(Antes, [mai | Depois], M).
Antes=[jan,fev,mar,abr] Depois=[jun,jul,ago,set,out,nov, dez]
e tambm achar o sucessor e o predecessor imediatos (os vizinhos) de um determinado item da lista:
?-conc(_, [X, g, Y | _], [a, b, c, d, e, f, g, h]).
X=f Y=h
possvel ainda apagar de uma lista todos os elementos que se seguem a um determinado padro. No
exemplo abaixo, retira-se da lista dos dias da semana a sexta-feira e todos os dias que a seguem.
?-conc(Trab, [sex | _], [seg,ter,qua,qui,sex,sab,dom]).
Trab=[seg,ter,qua,qui]
45
A prpria relao de ocorrncia, membro/2, vista na seo anterior pode ser reprogramada em funo
de conc/3:
membro1(X, L) :-
conc(_, [X | _], L).
Essa clusula nos diz que X membro de uma lista L se L pode ser decomposta em duas outras listas
onde a cabea da segunda X. Na verdade, membro1/2 define a mesma relao que membro/2, ape-
nas adotou-se um nome diferente para estabelecer uma distino entre ambas.
5.2.4 REMOO DE ELEMENTOS DE UMA LISTA
A remoo de um elemento X de uma lista L pode ser programada atravs da relao:
remover(X, L, L1)
onde L1 a mesma lista L com o elemento X removido. A relao remover/3 pode ser definida de
maneira similar relao de ocorrncia. Novamente so dois casos a estudar:
(1) Se X a cabea da lista L, ento L1 ser o seu corpo;
(2) Se X est no corpo de L, ento L1 obtida removendo X desse corpo.
Em Prolog, isso escrito da seguinte maneira:
remover(X, [X | C], C).
remover(X, [Y | C], [Y | D]) :-
remover(X, C, D).
Assim como a relao membro/2, remover/3 tambm no-determinstica por natureza. Se h diversas
ocorrncias de X em L, a relao remove/3 capaz de retirar cada uma delas atravs do mecanismo de
backtracking do Prolog. Evidentemente, em cada execuo do programa remove/3 retiramos somente
uma das ocorrncias de X, deixando as demais intocveis. Por exemplo:
?-remover(a, [a, b, a, a], L).
L=[b, a, a];
L=[a, b, a];
L=[a, b, a];
no
remover/3 ir falhar se a lista L no contiver nenhuma ocorrncia do elemento X. Essa relao pode
ser ainda usada no sentido inverso para inserir um novo item em qualquer lugar da lista. Por exemplo,
pode-se formular a questo: "Qual a lista L, da qual retirando-se 'a' , obtem-se a lista [b, c, d]?"
?-remover(a, L, [b, c, d]).
L=[a, b, c, d];
L=[b, a, c, d];
L=[b, c, a, d];
L=[b, c, d, a];
no
De modo geral, pode-se inserir um elemento X em algum lugar de uma lista L, resultando em uma
nova lista L1, com o elemento X inserido na posio desejada, por meio da clusula:
inserir(X, L, L1) :-
remover(X, L1, L).
Em membro1/2 foi obtida uma forma alternativa para a relao de ocorrncia, utilizando o predicado
conc/3. Pode-se obter a mesma relao por meio de remover/3:
membro2(X, L) :-
remover(X, L, _).
5.2.5 INVERSO DE LISTAS
46
A relao que inverte uma lista, isto , que organiza seus elementos na ordem inversa til para os
mais diversos propsitos. Abaixo temos alguns exemplos de inverso:
inverter([a, b, c], [c, b, a]).
inverter([], []).
inverter([a, [b, c], d], [d, [b, c], a])
Dentre os diversos mecanismos lgicos capazes de inverter uma lista, o denominado "inverso ing-
nua" baseia-se numa abordagem muito direta, embora seu tempo de execuo seja proporcional ao
quadrado do tamanho da lista:
(1) Tomar o primeiro elemento da lista;
(2) Inverter o restante;
(3) Concatenar a lista formada pelo primeiro elemento ao inverso do restante.
Em Prolog, escreve-se:
inverter([], []).
inverter([X | Y], Z) :-
inverter(Y, Y1),
conc(Y1, [X], Z).
Esse programa, juntamente com o predicado conc/3, costuma ser empregado como um teste ben-
chmark para sistemas Prolog. Quando o nmero de inferncias lgicas, ou chamadas de objetivos
Prolog dividido pelo nmero de segundos gastos, o nmero obtido mede a velocidade do sistema
Prolog em LIPS (logic inferences per second). A inverso de listas pode, entretanto ser obtida de
modo mais eficiente por meio de um predicado auxiliar, iterativo, aux/3, tornando o tempo de execu-
o apenas linearmente proporcional ao tamanho da lista a inverter:
inverter(X, Y) :-
aux([], X, Y).
aux(L, [], L).
aux(L, [X | Y], Z) :-
aux([X | L], Y, Z).
5.2.6 SUBLISTAS
Iremos considerar agora a relao sublista/2 que possui como argumentos uma lista S e uma lista L
tais que S ocorre em L como sublista. Assim, verdadeira a afirmao:
sublista([c, d, e], [a, b, c, d, e, f])
mas falso declarar que:
sublista([c, e], [a,b,c,d,e,f])
O programa Prolog para a relao sublista/2 pode se basear na mesma idia explorada na definio do
predicado membro1/2, com a diferena que, desta vez, a relao mais genrica, podendo ser formu-
lada por:
S sublista de L se:
(1) L pode ser decomposta em duas listas, L1 e L2, e
(2) L2 pode ser decomposta em S e L3.
Como foi visto anteriormente, a relao conc/3 pode ser usada para a decomposio de listas. Assim a
formulao acima pode ser expressa em Prolog por:
sublista(S, L) :-
conc(L1, L2, L),
conc(S, L3, L2).
O programa sublista/2 pode ser usado de modo bastante flexvel em diversas aplicaes. Apesar de ter
sido projetado para verificar se alguma lista ocorre como sublista de outra, ele pode, por exemplo, ser
47
usado para obter todas as sublistas de uma lista:
?-sublista(S, [a, b, c]).
S=[];
S=[a];
S=[a, b];
S=[a, b, c];
S=[b];
S=[b,c];
S=[c];
no
5.2.7 PERMUTAO DE LISTAS
Algumas vezes pode ser interessante gerar permutaes de uma dada lista. Com essa finalidade defi-
ne-se a relao permutar/2 cujos argumentos so duas listas tais que cada uma permutao da outra.
A inteno permitir a gerao de todas as permutaes possveis de uma dada lista empregando o
mecanismo de backtracking que pode ser disparado a partir da relao permutar/2, como por exemplo
em:
?-permutar([a, b, c], P).
P=[a, b, c];
P=[a, c, b];
P=[b, a, c];
P=[b, c, a];
P=[c, a, b];
P=[c, b, a];
no
O programa permutar/2 deve novamente basear-se na considerao de dois casos, dependendo da lista
a ser permutada:
(1) Se a primeira lista vazia, ento a segunda tambm ;
(2) Se a primeira lista no-vazia, ento possui a forma [X|L] e uma permutao de tal lista pode ser construda
primeiro permutando L para obter L1e depois inserindo X em qualquer posio de L1, conforme a Figura
5.3.
L X
L1
permutar L
inserir X obtendo uma
permutao de [X | L].
Figura 5.3 Permutao de Listas
A relao Prolog correspondente :
permutar([], []).
permutar([X | L], P) :-
permutar(L, L1),
inserir(X, L1, P).
O uso normal da relao permutar/2 seria como no exemplo dado anteriormente, permutar([a, b, c],
P). Uma tentativa diferente seria propor ao sistema:
?-permutar(L, [a, b, c]).
Aqui o programa dado ir, de incio, obter em L as seis permutaes existentes para [a, b, c], mas
depois, se o usurio pedir mais solues, o programa nunca ir responder "no", entrando em um lao
infinito na tentativa de encontrar outra permutao onde j no h mais nenhuma. Assim, algum cui-
dado necessrio no uso desta relao.
48
5.3 OUTROS EXEMPLOS
Dada a importncia do uso de listas em Prolog, apresenta-se informalmente na presente seo algumas
aplicaes adicionais definidas sobre listas que podem vir a ser de grande utilidade em programas
futuros, deixando-se ao leitor a tarefa de verificar o seu funcionamento segundo as diferentes inter-
pretaes estudadas.
5.3.1 TAMANHO DE UMA LISTA
A relao tamanho/2, representada por tamanho(L, T) ser verdadeira quando T for o nmero de ele-
mentos existentes em L:
tamanho([], 0).
tamanho([_ | R], N) :-
tamanho(R, N1),
N is N1+1.
Por exemplo:
?-tamanho([a, b, c, d, e], X).
X=5
5.3.2 SELEO DE ELEMENTOS PARTICULARES
Muitas vezes necessrio identificar em uma lista um determinado elemento que possua uma certa
propriedade. Isso pode ser realizado atravs da relao prop/2, abaixo, onde p/1 representa a proprie-
dade procurada, devendo estar definida no programa. Note a semelhana dessa relao com o predica-
do membro/2, anteriormente discutido.
prop(X, [X | _]) :-
p(X).
prop(X, [_ | Y]) :-
prop(X, Y).
Outras vezes necessrio selecionar exatamente o ensimo elemento de uma lista. O predicado en-
simo/3, a seguir, realiza esta funo:
ensimo(1, X, [X | _]).
ensimo(N, X, [_ | Y]) :-
ensimo(M, X, Y),
N is M+1.
Exemplos de utilizao desse predicado so:
?-ensimo(3, X, [a, b, c, d]).
X=c
?-ensimo(N, b, [a, b, c, d]).
N=2
Outra necessidade freqente reunir em um lista separada determinados elementos de uma lista,
identificados pela sua posio. Isso obtido pelo predicado seleciona/3, abaixo, que por sua vez em-
prega a relao ensimo/3:
seleciona([], _, []).
seleciona([M | N], L, [X | Y]) :-
ensimo(M, X, L),
seleciona(N, L, Y).
Por exemplo:
?-seleciona([2, 4], [a, b, c, d, e], L).
L=[b, d]
5.3.3 SOMA E PRODUTO
49
O somatrio e o produtrio de uma lista so dados respectivamente pelas relaes soma/2 e produto/2
abaixo. Observe o artifcio empregado na definio de produto/2, para garantir que o produtrio de
uma lista vazia seja zero.
soma([], 0).
soma([X | Y], S) :-
S is R+X,
soma(Y, R).
produto([], 0).
produto([X], X).
produto(L, P) :-
prod(L, P).
prod([], 1).
prod([X | Y], P) :-
P is Q*X,
prod(Y, Q).
Exemplos dos predicados soma/2 e produto/2 so dados abaixo:
?-soma([1, 2, 3, 4], X).
X=10
?-soma([1,2, X, 4], 10).
X=3
?-produto([], X).
X=0
?-produto([1, X, Y, 4], 24).
X=1 Y=6;
X=2 Y=3;
X=3 Y=2;
X=6 Y=1;
no
Este ltimo exemplo, apesar da interpretao declarativa correta, no domnio dos inteiros positivos,
poder no funcionar corretamente em todas as implementaes Prolog devido a caractersticas ope-
racionais particulares de irreversibilidade dos operadores aritmticos.
5.3.4 INTERSECO DE LISTAS
O predicado intersec/3, a seguir, computa a interseco de duas listas em uma terceira:
intersec([X | Y], L, [X |Z]) :-
membro(X, L),
intersec(Y, L, Z).
intersec([_ |X], L, Y) :-
intersec(X, L, Y).
ntersec(_, _, []).
Por exemplo:
?-intersec([a, b, c, d], [aa, b, d], L).
L=[b, d]
RESUMO
Listas so estruturas freqentemente usadas em Prolog. Estas podem ser vazias (representadas pelo tomo []),
ou constitudas por uma cabea (seu primeiro elemento) e um corpo (os demais);
A notao usual para listas emprega o functor "" (ponto) reunindo dois argumentos, a cabea e
o corpo, em uma nica lista. Por exemplo, (a, (b, (c, []))) representa a lista [a, b, c];
H uma notao simplificada em Prolog que permite a representao de listas na forma [H|T],
onde H a cabea e T o corpo da lista.
A cabea de uma lista pode ser qualquer termo Prolog, entretanto o corpo de uma lista sempre
ser uma lista;
50
H uma correspondncia entre listas e estruturas em rvore, permitindo que listas sejam ele-
mentos de outras listas;
Operaes comuns sobre listas apresentadas no presente captulo foram: construo, ocorrn-
cia, concatenao, insero, remoo, inverso, sublistas e permutaes de listas.
EXERCCIOS
5.1 Escreva um programa denominado acomoda/2 cujo primeiro argumento uma lista permitindo
listas como elementos, tal como [a, [a, [b, c]], b. [c, d]], e cujo segundo argumento outra lista
com todos os elementos da primeira acomodados em uma nica lista, como [a, a, b, c, b, c, d].
Por exemplo:
?-acomoda([a, [b], [c, d]], L).
L=[a, b, c, d]
Examine a reversibilidade do predicado obtido. O que possvel obter por meio de backtracking?
5.2 Qual o nmero de inferncias necessrio para computar o inverso de uma lista pelo mtodo da
inverso ingnua? Use-o para medir a velocidade em LIPS do seu sistema Prolog.
5.3 Escreva um programa que inverta uma lista de elementos e que tambm, recursivamente, inverta
esses prprios elementos quando eles forem listas.
5.4 Escreva um programa denominado
escore(X, Y, A, B)
onde X e Y so listas de inteiros do mesmo tamanho, A o nmero de posies que possuem
nmeros idnticos e B o nmero de elementos que ocorrem simultaneamente em ambas as lis-
tas, mas em posies diferentes. Por exemplo:
?-escore([7, 2, 3, 4], [2, 3, 4, 4], A, B).
A=1 B=2
5.5 Escreva um programa denominado
limpa(X, L1, L2)
que produz L2 como sendo L1 sem nenhuma ocorrncia do termo X .
5.6 Escreva um predicado denominado
palndromo(X)
que verdadeiro se X uma lista cujos elementos invertidos produzem a mesma ordem original.
Por exemplo:
?-palndromo([a, X, a, r, Y]).
X=r Y=a
5.7 Escreva um predicado denominado
estat(L, Max, Min, Med, DP)
onde L uma lista de nmeros, Max o maior destes nmeros, Min o menor, Med sua mdia arit-
mtica e DP o seu desvio padro.
5.8 Escreva um programa denominado
ordena(X, Y)
onde Y uma verso ordenada da lista X. Por exemplo:
?-ordena([9, 6, 5, 1, 6], L).
L=[1, 5, 6, 6, 9]
51
6. CONTROLE
Como j foi visto, o programador pode controlar a execuo de seu programa atravs da reordenao
das clusulas ou de objetivos no interior destas. Neste captulo se estudar um outro instrumento para
o controle de programas - denominado "cut" - que se destina a prevenir a execuo do backtracking
quando este no for desejado. Tambm se introduzir a "negao por falha", uma forma operacional
da negao lgica. Exemplos sero apresentados com a finalidade de ilustrar os conceitos desenvolvi-
dos.
6.1 BACKTRACKING
Na execuo dos programas Prolog, a evoluo da busca por solues assume a forma de uma rvore -
denominada "rvore de pesquisa" ou "search tree" - que percorrida sistematicamente de cima para
baixo (top-down) e da esquerda para direita, segundo o mtodo denominado "depth-first search" ou
"pesquisa primeiro em profundidade". A Figura 6.1 ilustra esta idia. Ali representada a rvore cor-
respondente execuo do seguinte programa abstrato, onde a, b, c, etc. possuem a sintaxe de termos
Prolog:
a :- b.
a :- c.
a :- d.
b :- e.
b :- f.
f :- g.
f :- h.
f :- i.
d.
a
b c d
e f
g h i

1
2
3 4
5 6 7
8 9
Figura 6.1 Ordem de visita aos nodos da rvore de pesquisa
O programa representado na figura acima ser bem sucedido somente quando o nodo d for atingido,
uma vez que este o nico fato declarado no programa. De acordo com a ordenao das clusulas, d
ser tambm o ltimo nodo a ser visitado no processo de execuo. O caminho percorrido dado
abaixo
a, b, e, (b), f, g, (f), h, (f), i, (f), (b), (a), c, (a), d
onde o caminho em backtracking representado entre parnteses.
52
Como foi visto, os objetivos em um programa Prolog podem ser bem-sucedidos ou falhar. Para um
objetivo ser bem-sucedido ele deve ser unificado com a cabea de uma clusula do programa e todos
os objetivos no corpo desta clusula devem tambm ser bem-sucedidos. Se tais condies no ocorre-
rem, ento o objetivo falha.
Quando um objetivo falha, em um nodo terminal da rvore de pesquisa, o sistema Prolog aciona o
mecanismo de backtracking, retornando pelo mesmo caminho percorrido, na tentativa de encontrar
solues alternativas. Ao voltar pelo caminho j percorrido, todo o trabalho executado desfeito. O
seguinte exemplo, sobre o predicado gosta/2 pode ajudar a esclarecer tais idias.
gosta(joo, jazz).
gosta(joo, renata).
gosta(joo, lasanha).
gosta(renata, joo).
gosta(renata, lasanha).
O significado intuitivo do predicado gosta(X, Y) "X gosta de Y". Supondo o conhecimento acima,
queremos saber do que ambos, joo e renata, gostam. Isto pode ser formulado pelos objetivos:
gosta(joo, X), gosta(renata, X).
O sistema Prolog tenta satisfazer o primeiro objetivo, desencadeando a seguinte execuo top-down:
1. Encontra que joo gosta de jazz
2. Instancia X com "jazz"
3. Tenta satisfazer o segundo objetivo, determinando se "renata gosta de jazz"
4. Falha, porque no consegue determinar se renata gosta de jazz
5. Realiza um backtracking na repetio da tentativa de satisfazer gosta(joo, X), esquecendo o
valor "jazz"
6. Encontra que joo gosta de renata
7. Instancia X com "renata"
8. Tenta satisfazer o segundo objetivo determinando se "renata gosta de renata"
9. Falha porque no consegue demonstrar que renata gosta de renata
10.Realiza um backtracking, mais uma vez tentando satisfazer gosta(joo, X), esquecendo o valor
"renata"
11.Encontra que joo gosta de lasanha
12.Instancia X com "lasanha"
13.Encontra que "renata gosta de lasanha"
14. bem-sucedido, com X instanciado com "lasanha"
O backtracking automtico uma ferramenta muito poderosa e a sua explorao de grande utilidade
para o programador. s vezes, entretanto, ele pode se transformar em fonte de ineficincia. A seguir
se introduzir um mecanismo para "podar" a rvore de pesquisa, evitando o backtracking quando este
for indesejvel.
6.2 O OPERADOR "CUT"
O papel desempenhado pelo operador "cut", de extrema importncia para semntica operacional dos
programas Prolog, permitindo declarar ramificaes da rvore de pesquisa que no devem ser retoma-
das no backtracking. Seu uso deve ser considerado pelas seguintes razes:
(i) O programa ir executar mais rapidamente, porque no ir desperdiar tempo tentando satisfa-
53
zer objetivos que no iro contribuir para a soluo desejada.
(ii)Tambm a memria ser economizada, uma vez que determinados pontos de backtracking no
necessitam ser armazenados para exame posterior.
Algumas das principais aplicaes do cut so as seguintes:
Unificao de padres, de forma que quando um padro encontrado os outros padres poss-
veis so descartados
Na implementao da negao como regra de falha
Para eliminar da rvore de pesquisa solues alternativas quando uma s suficiente
Para encerrar a pesquisa quando a continuao iria conduzir a uma pesquisa infinita, etc.
Sintaticamente o uso do cut em uma clusula tem a aparncia de um objetivo sem nenhum argumento,
representado por um ponto de exclamao "!".
Vamos estudar agora o comportamento de um pequeno programa que realiza algum backtracking des-
necessrio. Identificaremos onde isso ocorre e mostraremos como a eficincia do programa pode ser
melhorada. Considere a funo cujo grfico apresentado na Figura 6.2.
0 1 2 3 4 5 6 7 8 9 10
X
0
1
2
3
4
Y=F(X)
Figura 6.2 Uma funo em degraus
A relao entre X e Y para a funo apresentada na figura acima pode ser especificada, para o dom-
nio dos inteiros no negativos, por meio de trs regras:
(1) Se X < 3, ento Y = 0
(2) Se 3 X e X < 6, ento Y = 2
(3) Se 6 X, ento Y = 4
que podem ser escritas em Prolog como uma relao binria f(X, Y), como se segue:
f(X, 0) :- X < 3.
f(X, 2) :- 3 =< X, X < 6.
f(X, 4) :- 6 =< X.
Este programa assume que antes de f(X, Y) ser avaliada, X deve obrigatoriamente estar instanciada
para algum nmero, como requerido pelos operadores de comparao. Faremos duas experincias
com esse programa. Em cada uma delas ser identificada uma fonte de ineficincia no programa, que
ser removida com o uso do cut.
6.2.1 EXCLUSO MTUA
Vamos analisar o que ocorre quando a seguinte questo formulada:
?-f(1, Y), 2 < Y
54
Na execuo do primeiro objetivo, f(1, Y), Y instanciada com 0, de forma que o segundo objetivo
passa a ser 2 < 0, que obviamente falha e, por meio de backtracking, conduz avaliao das outras
duas regras que, por sua vez, tambm iro falhar. Esse raciocnio direto, entretanto, antes de tentar
as duas ltimas regras, j sabamos (ns humanos) que elas no funcionariam. A execuo completa
mostrada na Figura 6.3.
f(1, Y), 2<Y
1 =< 3
2 < 0
3 =< 1
1 < 6
2 < 2
6 =< 1
2 < 4
2 < 0
<--- cut: Aqui j sabemos que (2) e (3) sempre iro falhar.
(3) (2) (1)
Y=0 Y=2 Y=4
Figura 6.3 Execuo da consulta ?-f(1, Y), 2 < Y.
No exemplo apresentado na figura acima, no ponto indicado por "cut" no desdobramento da regra 1,
j conhecemos o seu intervalo de aplicao e sabemos que, se este estiver correto e o restante da regra
falhar, no h sentido em explorar outra alternativa. Para prevenir o sistema de apresentar um
backtracking desnecessrio, devemos indicar isto especificamente, o que feito atravs do mecanismo
de corte. Este representado explicitamente por um "!" e inserido entre os objetivos como uma es-
pcie de pseudo-objetivo que sempre bem sucedido quando ativado na direo top-down, mas que
sempre falha quando atingido atravs de backtracking, ocasionando ainda, como efeito colateral, a
falha de todas as demais clusulas do predicado onde o cut declarado. O programa do exemplo, re-
escrito com cuts assume o seguinte aspecto:
f(X, 0) :- X < 3, !.
f(X, 2) :- 3 =< X, X < 6, !.
f(X, 4) :- 6 =< X.
Aqui o smbolo "!" evita o backtracking nos pontos em que aparece no programa. Se agora novamente
fosse formulada a consulta ?-f(1, Y), 2<Y., o sistema Prolog iria inicialmente produzir o mesmo des-
vio mais esquerda apresentado na Figura 6.3. O caminho produzido na rvore de pesquisa ir falhar
no objetivo 2<0. O Prolog ir ento tentar o backtracking, mas no alm do ponto marcado com um
"!" no programa. Os desvios correspondentes s regras (2) e (3) no so gerados. O novo programa,
equipado com cuts, , em geral, de execuo mais eficiente do que a verso original, que no possui
cuts. Esta ir certamente produzir os mesmos resultados, apesar de ser menos eficientes. Pode-se di-
zer, neste caso, que a introduo de cuts afetou somente a interpretao operacional do programa, sem
interferir na sua interpretao declarativa. Veremos a seguir que o uso do cut pode afetar tambm o
significado declarativo do programa.
6.2.2 INTERFERINDO COM A INTERPRETAO DECLARATIVA
Efetuaremos uma segunda experincia, agora sobre a segunda verso do nosso programa. Seja a se-
guinte consulta, j acompanhada da soluo:
?-f(7, Y).
Y=4
55
Vamos analisar o que aconteceu. Todas as trs regras foram tentadas antes da resposta ter sido obtida,
produzindo a seguinte seqncia de objetivos:
(1) Tenta a regra (1): 7<3 falha. Aciona o backtracking e tenta a regra (2). O cut no foi atingido.
(2) Tenta a regra (2): 3=<7 bem-sucedido, mas 7<6 falha. Aciona o backtracking e tenta a regra
(3). O cut no foi atingido.
(3) Tenta a regra (3): 6=<7 bem-sucedido.
A sequncia permite identificar uma segunda fonte de ineficincia no programa. Primeiro estabele-
cido que X<3 no verdadeiro, pois 7<3 falha. O objetivo seguinte 3=<X que, se o primeiro objeti-
vo falhou, s pode ser verdadeiro, pois a negao dele. Portanto, o segundo teste redundante e o
objetivo correspondente pode ser omitido. O mesmo pode ser dito do objetivo 6=<X na regra (3). Isso
conduz a uma formulao ainda mais econmica do programa:
f(X, 0) :- X < 3, !.
f(X, 2) :- X < 6, !.
f(X, 4).
Este programa produz os mesmos resultados que a verso original, mas da forma mais eficiente vista
at agora. O que aconteceria entretanto se os cuts fossem removidos? O programa fica:
f(X, 0) :- X < 3.
f(X, 2) :- X < 6.
f(X, 4).
que pode produzir mltiplas solues, as quais nem sempre estaro corretas. Por exemplo:
?-f(1, Y).
Y=0; Y=2; Y=4;
no
importante notar aqui que, diferentemente da segunda verso, na terceira os cuts no afetam so-
mente o comportamento operacional do programa, mas tambm o seu significado declarativo. Uma
idia mais precisa do funcionamento do mecanismo de corte do Prolog o seguinte:
Vamos denominar "objetivo pai" o objetivo que unifica com a cabea da clusula que contm
o cut. Quando o cut encontrado, como um objetivo, ele sempre bem-sucedido, mas elimina
do sistema a pesquisa via backtracking de todas as clusulas entre o objetivo pai e o cut.
Por exemplo, considere-se a clusula:
H :- B1, B2, ..., Bm, !, ..., Bn.
Vamos assumir que ela tenha sido ativada por um objetivo G, que unifica com H. Ento G um obje-
tivo pai. No momento em que o cut encontrado o sistema j possui alguma soluo para os objetivos
B1, ..., Bm. Quando o cut executado, a soluo para B1, ..., Bm fica "congelada" e todas as demais
solues possveis so descartadas. Alm disso, o objetivo G agora passa a se limitar a essa clusula.
Qualquer tentativa de unificar G com com a cabea de alguma outra clusula fica impedida de se rea-
lizar. Vamos aplicar tais regras ao seguinte exemplo:
C :- P, Q, R, !, S, T, U.
C :- V.
A :- B, C, D.
?-A.
onde A, B, C, etc. possuem a sintaxe de termos Prolog. O cut ir afetar a execuo do objetivo C da
seguinte maneira: O backtracking possvel na seqncia de objetivos P, Q, R, entretanto, to logo o
cut alcanado todas as solues alternativas para os objetivos P, Q, R so descartadas. A clusula
alternativa para C, C V, tambm descartada, entretanto, o backtracking ainda possvel na lista de
objetivos S, T, U.
O objetivo pai da clusula contendo o cut C em A B, C, D. Portanto o cut ir afetar somente a
56
execuo de C, sendo completamente invisvel do ponto de vista de A. Assim o backtracking autom-
tico continua ativo independentemente do cut na clusula usada para satisfazer o objetivo C.
6.3 APLICAES DO CUT
Apresenta-se nesta seo alguns exemplos de pequenas aplicaes empregando o operador cut, visan-
do ilustrar o seu uso em programas reais.
6.3.1 MXIMO DE DOIS NMEROS
O procedimento para encontrar o maior de dois nmeros pode ser programado como uma relao
max(X, Y, Max), onde Max=X se X for maior ou igual a Y e Max=Y se este for maior que X. Isto
pode ser escrito em Prolog por meio das seguintes clusulas:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.
Essas duas regras so mutuamente exclusivas. Se a primeira for bem sucedida, ento a segunda certa-
mente ir falhar e vice-versa. Portanto uma forma mais econmica de representar o mesmo programa
com o uso do cut seria:
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y).
6.3.2 SOLUO NICA PARA A OCORRNCIA
No captulo anterior definiu-se a relao membro(X, L) para estabelecer se X est presente na lista L.
O programa era:
membro(X, [X|_]).
membro(X, [_|Y]) :-
membro(X, Y).
Essa soluo no-determinstica. Se X ocorre vrias vezes, ento qualquer ocorrncia pode ser en-
contrada. Vamos agora mudar o predicado membro/2, tornando-o um programa determinstico que ir
sempre encontrar a primeira ocorrncia de X. A modificao a fazer simples: apenas evitamos o
backtracking to logo X tenha sido encontrado, o que acontece quando a primeira clusula bem-
sucedida. O programa modificado fica:
membro(X, [X|_]) :- !.
membro(X, [_|Y]) :-
membro(X, Y).
e agora somente a primeira soluo ser encontrada. Por exemplo:
?-membro(X, [a, b, c, d]).
X=a;
no
6.3.3 ADIO DE ELEMENTOS SEM DUPLICAO
Freqentemente deseja-se adicionar um item X a uma lista L de modo que X seja adicionado a L so-
mente se X ainda no estiver em L. Se X j estiver em L, ento a lista permanecer a mesma, porque
no desejamos a duplicao dos elementos em L. Uma adio adicionar(X, L, L1), com essas caracte-
rsticas, pode ser formulada da seguinte maneira:
Se X membro da lista L, ento L1 = L
seno, L1 igual a L com a insero de X na cabea.
57
mais fcil inserir X como primeiro elemento, de modo que X se torna a cabea de L1 quando se
verifica a sua ausncia na lista. Em Prolog escreve-se:
adicionar(X, L, L) :-
membro(X, L), !.
adicionar(X, L, L1).
O comportamento desse programa pode ser ilustrado pelos exemplos abaixo:
?-adicionar(a, [b,c], L).
L=[a, b, c]
?-adicionar(X, [b,c], L).
X=b L=[b, c]
?-adicionar(a, [b, c, X], L).
X=a L=[b, c, a]
Esse exemplo instrutivo, porque no possvel programar facilmente a "adio sem duplicatas" sem
o uso do cut ou de alguma outra construo dele derivada. Portanto o cut necessrio aqui para espe-
cificar a relao correta e no somente para incrementar a eficincia do programa.
6.3.4 IF-THEN-ELSE
A programao procedimental estruturada pode ser simulada em Prolog. Neste exemplo a estrutura if-
then-else descrita atravs da relao:
ifThenElse(X, Y, Z)
que deve ser interpretada da seguinte maneira: "Se X for verdadeiro, ento execute Y, seno execute
Z". O programa Prolog :
ifThenElse(X, Y, _) X, !, Y.
ifThenElse(_, _, Z) Z.
Deve-se notar que este programa emprega meta-variveis (variveis que podem ser instanciadas com
chamadas a predicados), o que no diretamente representado em todas as implementaes Prolog.
Em sendo possvel, o exemplo abaixo ilustra a utilizao de tal programa:
?-ifThenElse(X, Y is Z+1, Y is 0).
Aqui, se o predicado representado por X for verdadeiro, a varivel Y ser instanciada com "Z+1",
caso contrrio, se X for falso, Y ser instanciada com o valor zero.
O emprego de meta-variveis requer alguma experincia em programao em lgica. Tal recurso no
deve ser aplicado indiscriminadamente sob pena de comprometer a legibilidade e o perfeito entendi-
mento do programa. Por outro lado, se bem utilizado, um recurso muito poderoso nas mos de um
bom programador.
6.4 NEGAO POR FALHA
"Maria gosta de todos os animais, menos de cobras". Como podemos dizer isto em Prolog? fcil
expressar uma parte dessa declarao: Maria gosta de X se X um animal, isto :
gosta(maria, X) animal(X).
mas necessrio ainda excluir as cobras. Isto pode ser conseguido empregando-se uma formulao
diferente:
Se X uma cobra,
ento no verdade que maria gosta de X
seno se X um animal, ento maria gosta de X.
Podemos dizer que alguma coisa no verdadeira em Prolog por meio de um predicado pr-definido
58
especial, "fail", que sempre falha, forando o objetivo pai a falhar. A formulao acima pode ser dada
em Prolog com o uso do fail da seguinte maneira:
gosta(maria, X) :-
cobra(X), !, fail.
gosta(maria, X) :-
animal(X).
Aqui a primeira regra se encarrega das cobras. Se X uma cobra, ento o cut evita o backtracking
(assim excluindo a segunda regra) e o fail ir ocasionar a falha da clusula. As duas regras podem ser
escritas de modo mais compacto como uma nica clusula, por meio do uso do conetivo ";":
gosta(maria, X) :-
cobra(X), !, fail;
animal(X).
Pode-se usar essa mesma idia para definir a relao diferente(X, Y) que, se for verdadeira, significa
que X e Y no unificam. Isto pode ser formulado por:
Se X e Y unificam
ento diferente(X, Y) falha
seno diferente(X, Y) bem-sucedido.
Em Prolog:
diferente(X, X) :- !, fail.
diferente(X, Y).
que tambm pode ser escrito sob a forma de uma s clusula:
diferente(X, Y) :- X=Y, !, fail; true.
onde "true" um objetivo pr-definido que sempre bem-sucedido. Esses exemplos indicam que seria
til dispor de um objetivo unrio "not" tal que not(Objetivo) seja verdadeiro se Objetivo no for ver-
dadeiro. A relao not/1 pode ser definida da seguinte maneira:
Se Objetivo bem-sucedido
ento not(Objetivo) falha
seno not(Objetivo) bem-sucedido.
que pode ser escrita em Prolog como:
not(P) :- P, !, fail; true.
A relao not/1 pr definida na maioria das implementaes Prolog e se comporta como o procedi-
mento apresentado acima. Vamos assumir ainda, como ocorre na maioria das vezes, que o not seja
definido como um operador prefixo, de modo que podemos escrever not(cobra(X)) como not co-
bra(X).
Deve ser notado que a relao not/1, definida como negao por falha, como foi feito, no correspon-
de exatamente negao da lgica matemtica. Essa diferena pode ocasionar um comportamento
inesperado do programa, se o not for usado sem cuidado. Apesar disso, o not um instrumento muito
til e pode ser utilizado com vantagem no lugar do cut. Os dois exemplos dados anteriormente poderi-
am ser escritos com o uso do not da seguinte maneira:
gosta(maria, X) :-
animal(X), not cobra(X).
diferente(X, Y) :-
not (X = Y).
que certamente so formulaes melhores que as anteriores. So mais naturais e mais fceis de ler.
6.5 CUIDADOS COM O CUT E A NEGAO
As vantagens e desvantagens do uso do cut foram ilustradas por meio de exemplos nas sees anterio-
res. Vamos resumir primeiro as vantagens:
59
Por meio do cut podemos freqentemente aumentar a eficincia dos programas Prolog. A idia
dizer explicitamente ao sistema: "No tente outras alternativas pois elas esto destinadas a
falhar".
Usando o cut podemos especificar regras mutuamente exclusivas, expressas na forma:
Se P ento Q seno R
realando desta maneira a expressividade da linguagem Prolog.
As reservas ao uso do cut vem do fato que podemos perder a valiosa correspondncia entre o signifi-
cado declarativo e a interpretao operacional do programa. Se no houver cuts no programa, pode-
mos trocar a ordem das clusulas e objetivos de modo que isso ir afetar apenas a eficincia do pro-
grama e no o seu significado declarativo. Por outro lado, em programas com cuts, uma modificao
na ordem das clusulas pode afetar o significado declarativo, conduzindo a resultados inesperados. O
ponto importante aqui que, quando se emprega o recurso do cut, deve-se atentar para os aspectos
operacionais envolvidos. Infelizmente essa dificuldade adicional aumenta a possibilidade de erro no
programa.
Nos exemplos dados nas sees anteriores viu-se que em alguns casos a remoo dos cuts podia alte-
rar o significado declarativo do programa. Em outros casos, entretanto, isso no ocorria, ou seja, o
emprego de cuts no ocasionava nenhum efeito sobre o significado declarativo. O uso de cuts desse
ltimo tipo menos delicado e por vezes estes so denominados "cuts verdes". Do ponto de vista da
legibilidade dos programas os cuts verdes so "inocentes" e o seu uso bastante aceitvel. Na leitura
dos programas os cuts verdes podem ser simplesmente ignorados.
Ao contrrio, os cuts que afetam o significado declarativo so denominados "cuts vermelhos" e so os
que tornam os programas difceis de serem lidos, devendo ser empregados com especial cuidado.
Os cuts so freqentemente utilizados em combinao com o predicado pr-definido fail/0. Em parti-
cular, definimos a negao de um objetivo (not) como sendo a falha deste objetivo. A negao assim
definida corresponde a uma forma mais restrita do uso do cut. Por razes de clareza deve-se preferir o
uso do operador not ao invs da combinao cut-fail sempre que possvel, porque a negao um
conceito de nvel mais elevado e entendida de forma intuitiva mais claramente do que a combinao
cut-fail.
Deve-se notar ainda que o uso do not pode tambm ocasionar alguns problemas e, portanto, esse ope-
rador deve tambm ser usado com cuidado. O problema que o not definido em Prolog como "ne-
gao por falha", que no corresponde exatamente negao da lgica matemtica. Se perguntarmos
ao sistema:
?-not humano(joo).
a resposta ser possivelmente "sim", entretanto isso no deve ser entendido como se o Prolog estives-
se dizendo que "joo no humano", mas na verdade que "no h informao suficiente no programa
que permita provar que joo humano". Isso acontece porque no processamento do objetivo not/1 o
Prolog no tenta prov-lo diretamente. Ao invs disso ele tenta provar o oposto e, se o oposto no
pode ser provado, ento ele assume que o objetivo not /1 bem-sucedido.
Tal raciocnio baseado na denominada "Hiptese do Mundo Fechado". Segundo tal hiptese, o
mundo fechado no sentido que "tudo o que existe est no programa ou pode ser dele derivado". As-
sim, se alguma coisa no est no programa (ou no pode ser dele derivada), ento no verdadeira e
consequentemente a sua negao verdadeira. Isso demanda cuidados especiais por parte do progra-
mador, uma vez que normalmente no se assume que "o mundo fechado", isto , no colocando
explicitamente a clusula humano(joo), no se estava querendo dizer que "joo no humano".
Finalmente, considere o seguinte programa:
60
r(a).
q(b).
p(X) :- not r(X).
Se consultarmos tal programa com:
?-q(X), p(X).
o sistema Prolog responder X=b, entretanto se a mesma consulta fosse formulada de modo "aparen-
temente" equivalente:
?-p(X), q(X).
a resposta seria "no". Convidamos o leitor a estabelecer o "trace" do programa de modo a entender
porque obtivemos respostas diferentes. A diferena chave entre as duas consultas reside no fato de
que, no primeiro caso., a varivel X j est instanciada quando p(X) executado, o que no ocorre no
segundo caso.
RESUMO
O uso do cut evita o backtracking. Esse recurso empregado tanto para aumentar a eficincia
dos programas quanto para realar a sua expressividade;
A eficincia aumentada dizendo explicitamente ao Prolog, por meio do cut, para no explorar
alternativas adicionais porque estas esto fadadas ao fracasso;
Por meio do cut possvel formular concluses mutuamente exclusivas por meio de regras da
forma:
Se Condio ento Concluso1 seno Concluso2;
O cut torna possvel introduzir a "negao por falha": not X definido em funo da falha de
X;
Dois predicados especiais pr-definidos so de grande utilidade em certos casos: o true/0 que
sempre bem sucedido e o fail/0 que sempre falha;
H alguma reserva quanto ao uso do cut. Sua insero em um programa pode destruir a corres-
pondncia entre os significados declarativo e operacional. Um bom estilo de programao deve
dar preferncia ao uso de "cuts verdes", que no afetam o significado declarativo do programa,
evitando os "cuts vermelhos" que o fazem;
O operador unrio not define uma forma particular de negao denominada "negao por fa-
lha", que no corresponde exatamente negao da lgica matemtica, de modo que o seu uso
tambm requer cuidados especiais.
EXERCCIOS
6.1 Seja o seguinte programa Prolog:
p(1).
p(2) :- !.
p(3).
Escreva todas as respostas do sistema Prolog para as seguintes consultas:
(a) ?-p(X).
(b) ?-p(X), p(Y).
(c) ?-p(X), !, p(Y).
6.2 A seguinte relao classifica nmeros em trs classes: positivo, nulo ou negativo:
classe(N, positivo) :- N > 0.
classe(0, nulo).
classe(N, negativo) :- N < 0.
61
Defina este procedimento de uma forma mais eficiente usando cuts.
6.3 Escreva um programa denominado
reparte(Nmeros, Positivos, Negativos).
que reparte uma lista de nmeros em duas listas: uma de nmeros positivos (incluindo o zero) e
outra de nmeros negativos. Por exemplo:
reparte([3,-1,0,5,-2], [3,0,5], [-1,-2]).
Proponha duas verses: uma com um nico cut e outra sem nenhum.
6.4 Defina o predicado:
unificvel(Lista1, Termo, Lista2)
onde Lista2 a lista de todos os elementos de Lista1 que unificam com Termo, deixando-os no
instanciados na resposta. Por exemplo:
?-unificvel([X, b, t(Y)], t(a), Lista).
Lista=[X, t(Y)]
Note que X e Y devem permanecer no-instanciados, apesar de a unificao com t(a) causar sua
instanciao. Dica: use not (Termo1=Termo2). Se Termo1=Termo2 for bem-sucedido, ento not
(Termo1=Termo2) falha e a instanciao realizada desfeita.
62
7. ESTRUTURAS DE DADOS
A possibilidade de empregar em Prolog estruturas de dados com unificao, backtracking e aritmtica
tornam essa linguagem de programao extremamente poderosa. No presente captulo estudaremos
estruturas de dados complexas por meio de exemplos de programas: recuperao de informao es-
truturada em uma base de dados, a simulao de um autmato no-determinstico e um planejamento
de roteiros de viagens. Tambm se introduzir o conceito de abstrao de dados em Prolog.
7.1 RECUPERAO DE INFORMAES
O exerccio apresentado a seguir desenvolve a habilidade de representar e estruturar objetos de dados
e tambm ilustra a viso do Prolog como uma linguagem natural de consulta a bases de dados. Consi-
dere a figura 7.1.
famlia
Pl
pessoa pessoa pessoa
data data
Ari Pl
trab
17
05
65
ibn
1500
data
Ana Pl
trab
06
11
68
rbz
1100
Ada Pl
nt
18
02
91
Figura 7.1 Informao estruturada sobre uma famlia
Uma base de dados pode ser naturalmente representada em Prolog como um conjunto de fatos. Por
exemplo, uma base de dados sobre famlias pode ser representada de modo que cada famlia seja des-
crita como um termo. A Figura 7.1 mostra como a informao sobre cada famlia pode ser estruturada
em um termo famlia/3, com a seguinte forma:
famlia(Pai, Me, Filhos)
onde Pai e Me so pessoas e Filhos uma lista de pessoas. Cada pessoa , por sua vez, representada
por uma estrutura com quatro componentes: nome, sobrenome, data de nascimento e trabalho. A data
de nascimento fornecida como um termo estruturado data(Dia, Mes, Ano). O trabalho, ou forneci-
do por um termo trab(Empresa, Salrio), ou pela constante nt, indicando que a pessoa em questo no
trabalha. A famlia exemplificada pode ento ser armazenada na base de dados como uma clusula do
tipo:
famlia(pessoa(ari, pl, data(17,05,65), trab(ibn,1500)),
pessoa(ana, pl, data(06,11,68), trab(rbs,1100)),
[pessoa(ada, pl, data(18,02,91), nt)] )
A base de dados poderia ser vista ento como uma seqncia de fatos, descrevendo todas as famlias
que interessam ao programa. A linguagem Prolog , na verdade, muito adequada para a recuperao
da informao desejada a partir de uma base de dados. Um detalhe muito interessante que os objetos
desejados no precisam ser completamente especificados. Pode-se simplesmente indicar a estrutura
63
dos objetos que interessam e deixar os componentes particulares apenas indicados. Por exemplo, se
queremos recuperar todas as famlias "Oliveira", basta especificar:
?-famlia(pessoa(_, oliveira, _, _), _, _).
ou as famlias cujas mes no trabalham:
?-famlia(_, pessoa(_, _, _, nt), _).
as famlias que no possuem filhos:
?-famlia(_, _, []).
ou ainda famlias que possuem trs ou mais filhos:
?-famlia(_, _, [_, _, _| _]).
As possibilidades de consulta so as mais diversas. Com esses exemplos queremos demonstrar que
possvel especificar os objetos de interesse, no pelo seu contedo, mas sim pela sua estrutura, sobre a
qual restringimos os componentes conforme nossas necessidades e/ou disponibilidades, deixando os
demais indefinidos. Na Figura 7.2 apresentado um programa demonstrando algumas das relaes
que podem ser estabelecidas em funo de uma base de dados estruturada na forma definida por fa-
mlia/3:
pai(X) :-
famlia(X, _, _).
me(X) :-
famlia(_, X, _).
filho(X) :-
famlia(_, _, Filhos),
membro(X, Filhos).
membro(X, [X|_]).
membro(X, [_|Y]) :-
membro(X, Y).
existe(Pessoa) :-
pai(Pessoa);
me(Pessoa);
filho(Pessoa).
nasceu(pessoa(_, _, Data, _), Data).
salrio(pessoa(_, _, _, trab(_,S)), S).
salrio(pessoa(_, _, _, nt), 0).
Figura 7.2 Um programa baseado na relao famlia/3
Algumas aplicaes para os procedimentos mostrados na figura acima podem ser encontrados nas
seguintes consultas base de dados:
Achar o nome e sobrenome de todas as pessoas existentes na base de dados:
?-existe(pessoa(Nome, Sobrenome, _, _)).
Achar todas as crianas nascidas em 1993:
?-filho(X), nasceu(X, data(_,_,93)).
Achar todas as pessoas desempregadas que nasceram antes de 1976:
?-existe(pessoa(_, _, data(_,_,A), nt), A < 76.
Achar as pessoas nascidas aps 1965 cujo salrio maior do que 5000:
?- existe(Pessoa),
nasceu(Pessoa, data(_,_,A)),
A > 65,
salrio(Pessoa, Salrio),
Salrio > 5000.
Para calcular o total da renda familiar, pode ser til definir a soma dos salrios de uma lista de pesso-
as como uma relao de dois argumentos:
64
total(L, T)
que pode ser declarada em Prolog como mostrado abaixo:
total([], 0).
total([Pessoa | Lista], Total) :-
salrio(Pessoa, Salrio)
total(Lista, Soma),
Total is Soma + Salrio.
Esta relao nos permite interrogar a base de dados para saber a renda familiar de cada famlia:
?-famlia(Pai, Me, FIlhos), total([Pai, Me | Filhos], RFam).
7.2 ABSTRAO DE DADOS
O conceito de "abstrao de dados" pode ser entendido como um processo de organizao de diversas
peas de conhecimento ou informao em uma forma conceitualmente significativa. Cada uma dessas
unidades de informao deveria ser facilmente acessada no programa. Idealmente, todos os detalhes
de implementao dessa estrutura deveriam ser invisveis ao usurio. O programador pode ento con-
centrar-se nos objetos e nas relaes existentes entre eles. A idia principal permitir ao usurio o uso
de informao complexa sem que seja necessrio envolv-lo com detalhes de representao. Discuti-
remos aqui uma forma de utilizar esse princpio.
Considere novamente o exemplo dado para a caracterizao de uma famlia na seo anterior. Cada
famlia uma coleo de peas de informao. Tais peas ficam armazenadas em unidades naturais,
como pessoa/4 ou famlia/3, de modo que podem ser tratadas como objetos simples. Assuma nova-
mente que a informao sobre uma determinada famlia se estruture na forma apresentada na Figura
7.1. Vamos agora definir algumas relaes atravs das quais o usurio pode acessar componentes
particulares da estrutura famlia/3, sem conhecer os detalhes de particulares empregados na sua repre-
sentao. Tais relaes so denominadas "seletoras", uma vez que elas selecionam componentes par-
ticulares da estrutura sobre a qual se aplicam. Normalmente o nome de cada relao seletora ser o
prprio nome do objeto que ele seleciona e os seus argumentos sero dois: primeiro, o objeto que
representa a estrutura da qual desejamos selecionar um determinado componente. Depois, o prprio
componente a ser selecionado. Alguns exemplos de relaes seletoras para a estrutura famlia/3 so
mostrados a seguir:
pai(famlia(Pai, _, _), Pai).
me(famlia(_, Me, _), Me).
primognito(famlia(_, _, [Prim | _]), Prim).
Outro objeto do qual podemos selecionar componentes pessoa/4. Alguns exemplos so:
empresa(pessoa(_, _, _, trab(Empr,_)), Empr).
sobrenome(pessoa(_, Sobrenome, _, _), Sobrenome).
Uma vez que as relaes seletoras estejam definidas, o usurio pode esquecer a forma particular usada
na representao de sua estrutura original. Para criar e manipular tal informao necessrio somente
conhecer os nomes das relaes seletoras e empregar tais nomes ao longo do programa. No caso de
representaes complicadas, isso muito mais simples do que usar a representao original de modo
implcito. No exemplo da relao famlia/3, o usurio no precisa saber que os filhos so representa-
dos por uma lista.
O uso de relaes seletoras tambm torna os programas mais fceis de modificar. Suponha que fosse
desejado aumentar a eficincia de um programa, mudando a forma de representar sua informao.
Tudo que necessrio fazer mudar as definies das relaes seletoras e o restante do programa
funcionar sem qualquer alterao com a nova representao.
65
7.3 UM AUTMATO FINITO NO-DETERMINSTICO
O exemplo apresentado na presente seo mostra como uma construo matemtica abstrata pode ser
descrita em Prolog. Alm disso, o programa final resultante mostrar ser muito mais poderoso e flex-
vel do que originalmente planejado. Um autmato finito no determinstico uma mquina abstrata
que l, como entrada, um string de smbolos e decide se deve aceitar ou rejeitar o string lido. O aut-
mato possui um certo nmero de estados e est sempre em um desses estados. O estado pode ser mu-
dado pela troca de um estado para outro, em decorrncia da situao em que o autmato se encontra.
A estrutura interna de um autmato pode ser representada por um grafo de transio, como mostrado
na Figura 7.3.
b
s2
s4 s3
s1
nulo
nulo
a
b
b
a
Figura 7.3 Um autmato finito no determinstico
No exemplo ali apresentado, s1, s2, s3 e s4 so os "estados" do autmato. A partir do estado inicia, s1
no exemplo dado, o autmato muda de estado para estado medida em que vai lendo o string de en-
trada. As transies de estado do autmato dependem do smbolo de entrada correntemente lido, con-
forme indicado pelas legendas dos arcos no grafo de transio.
Uma transio ocorre toda vez que um smbolo do string de entrada lido. Note que a transio, como
representada na Figura 7.3 no-determinstica. Se o autmato estiver em s1, e o smbolo de entrada
"a" , ento a transio pode ser realizada tanto para s1 quanto para s2. Alguns arcos so rotulados
como "nulo" para denotar o "smbolo nulo". Tais arcos correspondem ao que se denomina "movi-
mentos silenciosos" do autmato. Esses so denominados "silenciosos" porque eles ocorrem sem que
haja qualquer leitura de smbolos a partir do string de entrada e o observador, visualizando o autmato
como uma "caixa-preta" no capaz de notar que uma transio de estado ocorreu. O estado s3 re-
presentado em negrito para denotar que este um "estado terminal", onde possvel encerrar a ao
do autmato. Dizemos que o autmato "aceitou" o string de entrada se h um caminho de transies
no grafo tal que:
(1) Comea no estado inicial,
(2) Termina no estado final, e
(3) As legendas dos arcos ao longo do caminho de transies correspondem ao string de entrada.
Fica inteiramente a critrio do autmato decidir quais das possveis transies sero executadas num
dado instante. Em particular, o autmato pode escolher entre realizar ou no um movimento silencio-
so, se este for possvel a partir do estado corrente. Os autmatos abstratos no-determinsticos desse
tipo possuem ainda uma propriedade "mgica": se h possibilidade de uma escolha ocorrer, esta
feita do modo "correto", isto , de um modo que conduza aceitao do string de entrada, se tal modo
existir. O autmato da Figura 7.3 ir, por exemplo, aceitar os strings "ab" e "aabaab", mas ir rejeitar
66
os strings "abb" e "abba". fcil demonstrar que o autmato aceita qualquer string que termina em
"ab" e rejeita todos os demais. Autmatos como esse podem ser descritos por meio de trs relaes:
(1) Uma relao unria, final/1, que define os estados finais do autmato;
(2) Uma relao de trs argumentos, trans/3, que define as transies de estado de forma que
trans(S1, X, S2)
significa que uma transio do estado S1 para o estado S2 possvel quando o smbolo de en-
trada X for lido;
(3) Uma relao binria, silncio(S1, S2), significando que um "movimento silencioso" possvel
de S1 para S2.
Para o autmato apresentado na Figura 7.3 essas trs relaes podem ser formuladas em Prolog da
seguinte maneira:
final(s3).
trans(s1, a, s1).
trans(s1, a, s2).
trans(s1, b, s1).
trans(s2, b, s3).
trans(s3, b, s4).
silncio(s2, s4).
silncio(s3, s1).
Representaremos os strings de entrada como listas, de modo que o string "aab" ser representado por
[a, a, b]. Dada a descrio do autmato, o simulador processar um determinado string de entrada e
decidir se este deve ser aceito ou rejeitado. Por definio, os autmatos no-determinsticos aceitam
um dado string se, partindo de um estado inicial, aps ter lido o string completo o autmato pode estar
em seu estado final. O simulador programado por meio de uma relao binria, aceita/2, que define
a aceitao de um determinado string a partir de um estado inicial. Assim a relao
aceita(Estado, String).
verdadeira se o autmato, a partir do de um estado inicial "Estado", aceita o string "String". A rela-
o aceita/2 pode ser definida por meio de trs clusulas, que correspondem aos trs casos seguintes:
(1) O string vazio, [], aceito a partir de um determinado estado S se S um estado final;
(2) Um string no-vazio aceito a partir de um estado S, se a leitura do primeiro smbolo no string
pode conduzir o autmato a algum estado S1 e o resto do string aceito a partir de S1;
(3) Um string aceito a partir de um estado S, se o autmato pode realizar um movimento silencio-
so de S para S1, e ento aceitar o string completo a partir de S1.
Esses trs casos originam as seguintes clusulas:
aceita(S, []) :-
final(S).
aceita(S, [X | R]) :-
trans(S, X, S1), aceita(S1, R).
aceita(S, L) :-
silncio(S, S1), aceita(S1, L).
Por meio dessa relao possvel perguntar se um determinado string aceito pelo autmato. Por
exemplo:
?-aceita(s1, [a, a, a, b]).
sim
Como foi visto anteriormente, os programas Prolog so frequentemente capazes de solucionar pro-
blemas mais gerais do que aqueles para os quais foram originalmente concebidos. No presente caso,
podemos por exemplo perguntar ao simulador a partir de quais estados ele aceitaria um determinado
string:
67
?-aceita(S, [a, b]).
S=s1; S=s3;
no
Outra possibilidade seria perguntar quais so os strings de trs smbolos que so aceitos pelo aut-
mato a partir de um determinado estado:
?-aceita(s1, [X, Y, Z]).
X=a Y=a Z=b;
X=b Y=a Z=b;
no
possvel ainda realizar diversos outros experimentos envolvendo questes ainda mais gerais, como
por exemplo: "a partir de que estados o autmato aceitar strings de tamanho sete?", etc. Experimen-
tos ainda mais complexos podem inclusive requerer modificaes na estrutura do autmato, mudando
as relaes final/1, trans/3 e silncio/2.
7.4 PLANEJAMENTO DE ROTEIROS AREOS
Na presente seo iremos construir um programa para auxiliar o planejamento de roteiros areos.
Apesar de bastante simples, o programa ser capaz de responder questes tais como:
Em que dias da semana h vos entre o Rio e Munique?
Como se pode chegar a Tquio partindo de Porto Alegre numa tera-feira?
Tenho que visitar Montevidu, Buenos Aires e Assuno, partindo de Braslia numa tera-feira
noite e chegando ao Rio na sexta-feira para o fim-de-semana. Em que seqncia deve ser rea-
lizada a viagem de forma que eu no tenha de fazer mais de um vo por dia?
O programa ser desenvolvido em funo de uma base de dados possuindo informaes sobre os vos,
representada por meio de uma relao com trs argumentos:
horrio(Cidade1, Cidade2, ListaDeVos).
onde ListaDeVos uma lista de termos estruturados na forma:
Partida/Chegada/CdVo/DiasDaSemana
Partida e Chegada representam termos contendo os horrios de partida, em Cidade1, e chegada em
Cidade2. CdVo uma constante utilizada na identificao do vo. DiasDaSemana uma lista con-
tendo os dias da semana em que o vo realizado, ou a constante "todos", significando que o vo
realizado todos os dias. Uma clusula da relao horrio/3 poderia ser, por exemplo:
horrio('porto alegre', miami, [12:30/21:00/vrg127/todos, 15:30/24:00/vrg911/[seg,qua,sex]]).
Os horrios so representados como objetos estruturados com dois componentes, horas e minutos,
separados por ":". O problema principal ser encontrar uma rota exata entre duas cidades, partindo em
um determinado dia da semana. Isso ser programado como uma relao de quatro argumentos:
rota(Cidade1, Cidade2, Dia, Rota)
onde Rota uma seqncia de vos que satisfaz aos seguintes critrios:
(1) O ponto de partida da Rota Cidade1;
(2) O ponto de chegada da Rota Cidade2;
(3) Todos os vos so no mesmo dia Dia;
(4) Todos os vos em Rota esto na relao horrio/3;
(5) H tempo suficiente para as transferncias de vo.
A rota representada por uma lista de termos estruturados na forma:
De-Para : CdVo : Partida
68
e sero empregados os seguintes predicados auxiliares:
(1) vo(Cidade1, Cidade2, Dia, CdVo, Partida, Chegada): dizendo que h um vo (CdVo) en-
tre Cidade1 e Cidade2, no dia da semana Dia, que parte no horrio de Partida e chega no hor-
rio de Chegada;
(2) partida(Rota, Hora): A partida da rota Rota ocorre na hora Hora;
(3) transferncia(Hora1, Hora2): H pelo menos 40 minutos entre Hora1 e Hora2, que devem ser
suficientes para a transferncia entre dois vos.
O problema de encontrar uma rota, dadas as condies apresentadas, em muitos pontos semelhante
simulao de um autmato finito no-determinstico apresentada na seo anterior. Os pontos comuns
aos dois problemas so:
Os estados do autmato correspondem s cidades;
Uma transio entre dois estados corresponde a um vo entre duas cidades;
A relao trans/3 do autmato corresponde relao horrio/3 do planejador de vo;
O simulador do autmato encontra um caminho no grafo de transio entre um estado inicial e
um estado final. O planejador de vo encontra uma rota entre a cidade de partida e a cidade
destino da viagem.
No portanto surpresa que a relao rota/4 possa ser definida de maneira semelhante relao acei-
ta/2. Uma vez que agora no h "movimentos silenciosos", devemos nos concentrar em dois casos:
(1) Vo Direto: Se h um vo direto entre as cidades C1 e C2, ento a rota consiste em um nico
vo:
rota(C1, C2, Dia, [C1-C2:CodVo:Partida]) :-
vo(C1,C2,Dia,CodVo,Partida,Chegada).
(2) Vo com Conexes: A rota entre C1 e C2 consiste em: primeiro um vo de C1 para alguma ci-
dade intermediria, C3, seguida por uma rota entre C3 e C2. Alm disso, deve haver tempo su-
ficiente entre a chegada de um vo e a partida do seguinte para a transferncia de avio:
rota(C1,C2,Dia,[C1-C3:CodVo1:Partida1 | Rota]) :-
rota(C2, C3, Dia, Rota),
vo(C1, C3, Dia, CodVo1, Partida1, Chegada1),
partida(Rota, Partida2),
transferncia(Chegada1, Partida2).
As relaes auxiliares vo/6, partida/2 e transferncia/2 so facilmente programadas e esto definidas
juntamente com o programa completo de planejamento de roteiros areos, apresentado na Figura 7.4,
onde tambm se encontra includo um pequeno exemplo da base de dados construda com a relao
horrio/3.
O planejador de roteiros areos ali apresentado, apesar de extremamente simples pode resolver com
eficincia o planejamento de rotas areas desde que a base de dados no seja demasiadamente grande.
Para esses casos seria necessrio um planejador mais eficiente que permitisse lidar com um nmero
muito grande de rotas alternativas.
69
:- op(50, xfy, ':').
vo(C1, C2, Dia, NVo, Part, Cheg) :-
horrio(C1, C2, LVos),
membro(Part/Cheg/NVo/Dias, LVos),
diaV(Dia, Dias).
membro(X, [X | _]).
membro(X, [_ | Y]) :-
membro(X, Y).
diaV(Dia, todos).
diaV(Dia, Dias) :-
membro(Dia, Dias).
rota(C1, C2, Dia, [C1-C2:NVo:Part]) :-
vo(C1, C2, Dia, NVo, Part, _).
rota(C1, C2, Dia, [C1-C3:NVo1:Part1 | Rota]) :-
rota(C3, C2, Dia, Rota),
vo(C1, C3, Dia, NVo1, Part1, Cheg1),
partida(Rota, Part2),
transferncia(Cheg1, Part2).
partida([C1-C2:NVo:Part | _], Part).
transferncia(H1:M1; H2:M2) :-
60 * (H2 - H1) + (M2 -M1) >= 40.
horrio(poa, rio, [12:30/14:10/vrg501/todos]).
horrio(rio, poa, [12:30/14:10/vrg502/todos]).
horrio(rio, mtv, [14:00/16:45/vrg660/[seg,qua,sex]]).
horrio(rio, bue, [15:00/18:00/aar601/todos]).
horrio(rio, ass, [08:00/09:50/vrg915/todos]).
horrio(rio, par, [10:30/20:45/afr333/todos]).
horrio(rio, tok, [08:00/22:00/jar712/[ter,qui,sab]]).
horrio(bue, rio, [10:00/13:30/aar180/todos]).
horrio(mtv, rio, [17:00/19:30/vrg661/todos]).
horrio(ass, rio, [17:00/19:00/vrg916/todos]).
horrio(par, nyc, [07:00/15:00/pan379/todos]).
Figura 7.4: Um planejador de roteiros areos e um exemplo de base de dados
RESUMO
Uma base de dados pode ser naturalmente representada em Prolog como um conjunto de fatos;
Os mecanismos de consulta e unificao do Prolog podem ser usados com grande flexibilidade
na recuperao de informao estruturada em uma base de dados. Adicionalmente, procedi-
mentos utilitrios podem ser facilmente desenvolvidos para melhorar a comunicao com a
base de dados;
O conceito de abstrao de dados pode ser visto como uma tcnica de programao que facilita
o uso de estruturas de dados muito complexas e contribui para a legibilidade dos programas.
muito natural para a linguagem Prolog lidar com os princpios bsicos da abstrao de dados;
Construes matemticas abstratas, como os autmatos, podem freqentemente ser traduzidas
diretamente para especificaes executveis em Prolog;
O mesmo problema pode muitas vezes ser abordado de diversas maneiras distintas, pela varia-
o de sua representao. A introduo de redundncias nessa representao pode muitas vezes
ocasionar economia de computao;
Muitas vezes o passo chave para a soluo de um problema a generalizao desse problema.
Paradoxalmente, considerando-se o problema de forma mais abrangente, pode-se muitas vezes
formular a soluo de maneira mais fcil.
EXERCCIOS
7.1 Escreva as consultas necessrias para extrair as seguintes informaes da base de dados "fam-
lia":
(a) As famlias que no tem filhos;
70
(b) Todos os filhos que trabalham;
(c) As famlias em que o pai est desempregado;
(d) As crianas cujos pais possuem uma diferena de idade superior a 15 anos;
(e) As famlias cuja renda per capita inferior a 1000.
7.2 Defina as seguintes relaes sobre a base de dados "famlia":
(a) gmeos(Filho1, Filho2), onde Filho1 e Filho2 so irmos gmeos;
(b) ensimoFilho(N, Filho), onde Filho o N
o
filho de uma famlia.
7.3 Defina uma relao aceita(Estado, String, Max), onde Max o tamanho mximo do string String
que pode ser aceito a partir do estado Estado do autmato apresentado na Figura 7.3.
7.4 Considere um tabuleiro de xadrez onde as casas so representadas por pares de coordenadas na
forma X/Y, assumindo X e Y valores entre 1 e 8.
(a) Defina a relao salta(Casa1, Casa2) de acordo com o movimento do cavalo no tabuleiro.
Assuma que Casa1 est sempre instanciada para a posio corrente do cavalo e que Casa2
pode ou no estar instanciada;
(b) Defina a relao caminho(Lista), onde Lista uma lista de casas que representam um ca-
minho vlido para um cavalo em um tabuleiro vazio;
(c) Formular a consulta necessria para, empregando a relao caminho/1 definida em (b), en-
contrar o caminho que o cavalo deve percorrer para, iniciando em uma casa qualquer, per-
correr todas as casas do tabuleiro, encerrando o trajeto no mesmo ponto de partida.
7.5 Escreva a consulta necessria ao planejador de roteiros areos para definir como possvel, par-
tindo de Porto Alegre numa segunda-feira, visitar Assuno, Buenos Aires e Montevidu, retor-
nando a Porto Alegre na quinta-feira efetuando no mais que um vo por dia.
71
8. ENTRADA E SADA
Neste captulo estudaremos alguns recursos embutidos, presentes na maioria das implementaes
Prolog, destinados leitura e gravao de dados em arquivos. Tais recursos podem tambm ser em-
pregados pelo usurio para a formatao de objetos no programa, de modo a atingir alguma represen-
tao externa desejada para tais objetos. Tambm introduziremos os recursos para a leitura de pro-
gramas e para a construo e decomposio de tomos e termos.
8.1 ARQUIVOS DE DADOS
O mtodo de comunicao entre o usurio e o programa que estivemos usando at agora consiste em
consultas realizadas pelo usurio que so respondidas pelo programa por meio de instanciaes de
variveis. Esse mtodo simples e prtico e, apesar de sua simplicidade, suficiente para obter a
entrada e sada de informaes. Muitas vezes, entretanto, tal mtodo no suficientemente adequado
tendo em vista a sua rigidez. Extenses a esse mtodo bsico tornam-se necessrias nos seguintes
casos:
Entrada de dados sob forma diferente das consultas, por exemplo, sob a forma de sentenas em
linguagem natural,
Sada de informaes em qualquer formato desejado, e
Entrada e sada para qualquer arquivo perifrico do computador e no somente para o terminal
do usurio.
Predicados pr-definidos, construdos com o objetivo de apoiar tais intenes so dependentes de
cada particular implementao da linguagem Prolog. Aqui se introduz um repertrio simples, que se
encontra presente na maioria dessas implementaes, apesar disso, o manual especfico do Prolog
utilizado deve ser consultado para detalhes.
Inicialmente se estudar o problema de direcionar a entrada e sada de dados para arquivos e, depois,
como os dados podem entrar e sair em diferentes formatos. A Figura 8.1 mostra uma situao geral
onde um programa Prolog se comunica com diversos arquivos:
Terminal
do
Usurio
Programa
Prolog
Arquivo
1
Arquivo
2
Arquivo
3
Arquivo
4
Fontes de
Entrada
Fontes de
Sada
Figura 8.1: Comunicao entre um programa Prolog e diversos arquivos
Como pode ser visto na figura acima, o programa pode se comunicar com diversos arquivos, receben-
do informaes das denominadas "fontes de entrada" e transmitindo informaes s denominadas
"fontes de sada". Os dados que vem do terminal do usurio so tratados como uma outra fonte de
entrada qualquer. Da mesma forma, os dados transmitidos ao terminal do usurio so tratados como
uma fonte de sada. Esses dois pseudo-arquivos so nomeados pela constante "user". Os nomes dos
outros arquivos podem ser escolhidos pelo programador de acordo com as regras adotadas em cada
particular implementao.
72
A qualquer momento da execuo de um programa Prolog, somente dois arquivos esto ativos: um
para entrada e outro para sada. Esses dois arquivos se denominam respectivamente "fonte de entrada
corrente" e "fonte de sada corrente.. No incio da execuo essas duas fontes correspondem ao termi-
nal do usurio. A fonte de entrada corrente pode ser mudada a qualquer momento para um outro ar-
quivo qualquer, digamos "novoArqEnt", por meio do objetivo:
see(novoArqEnt).
Esse objetivo sempre bem sucedido (a menos que haja alguma coisa errada com NovoArqEnt. Um
exemplo tpico de utilizao do predicado see/1 a seguinte seqncia de objetivos, que l alguma
coisa de um certo arquivo, "arq1", e ento retorna ao terminal do usurio:
...
see(arq1).
l_do_arquivo(Informao).
see(user).
...
A fonte de sada corrente pode tambm ser mudada por um objetivo da forma:
tell(novoArqSai).
Uma seqncia de objetivos para enviar alguma informao para "arq3" e depois redirecionar a sada
para o terminal do usurio poderia ser:
...
tell(arq3).
grava_no_arquivo(Informao).
tell(user).
...
Dois outros predicados pr-definidos que devem ser mencionados aqui so seen/0 e told/0, cujo efeito
fechar os arquivos correntes de entrada e sada respectivamente.
Os arquivos podem ser processados somente na forma sequencial. nesse sentido, todos os arquivos se
comportam da mesma maneira que o terminal do usurio. Cada requisio para a leitura de alguma
coisa a partir de alguma fonte de entrada ir ocasionar a leitura a partir da posio corrente dessa
fonte de entrada. Aps a leitura, a posio corrente dessa fonte de entrada ser, naturalmente, o pr-
ximo item que ainda no foi lido, de forma que uma nova requisio de leitura ir iniciar a ser execu-
tada iniciando nessa nova posio corrente. Se uma requisio de leitura feita para o fim do arquivo,
ento a informao devolvida ser a constante "end_of_file", indicandio que o fim do arquivo foi
atingido. Uma vez que alguma informao foi lida, no possvel l-la novamente a menos que se
retome a leitura do arquivo a partir do incio.
A sada de informaes ocorre de maneira similar. Cada requisio de sada ir adicionar a informa-
o requisitada no final da fonte de sada corrente. Da mesma forma que na leitura, no possvel
retornar e reescrever sobre a poro do arquivo que j foi escrita.
Todos os arquivos so do tipo "texto", isto , arquivos de caracteres. Os caracteres podem ser letras,
dgitos, ou de algum tipo especial. Alguns desses ltimos so ditos ser "no-imprimveis" porque
quando so direcionados para o terminal do usurio eles no aparecem no vdeo. Podem, no entanto,
possuir algum outro efeito como o espaamento entre colunas e linhas, reposicionamento do cursor,
etc.
H duas maneiras diferentes de se utilizar os arquivos em Prolog, dependendo da forma que se deseja
empregar para os dados. A primeira delas considera o caracter como o elemento bsico do arquivo.
Assim uma requisio de entrada ou sada ocasionar a leitura ou escrita de um nico caracter. Os
predicados pr-definidos para tratar essa modalidade de arquivo so get/1, get0/1 e put/1.
A outra forma de utilizar arquivos em Prolog considerar unidades maiores de informao como ele-
mentos bsicos de entrada e sada. Tais unidades so os termos Prolog. Assim, cada requisio de
73
entrada ou sada desse tipo ir ocasionar a transferncia de um termo inteiro. Os predicados que exe-
cutam a transferncia de termos so read/1 e write/1. Naturalmente, nesse caso, a informao dever
se encontrar numa forma que seja consistente com a sintaxe dos termos Prolog.
O tipo de organizao a ser escolhido para um determinado arquivo depende naturalmente do proble-
ma que se est tentando resolver, entretanto, sempre que a especificao do problema permitir, iremos
preferir trabalhar com arquivos de termos, que permitem a transferncia de uma unidade significativa
completa atravs de uma nica requisio. Por outro lado, h problemas cuja natureza determina o
emprego de alguma outra organizao. Um exemplo o processamento de sentenas em linguagem
natural para, digamos, estabelecer um dilogo com o usurio. Em tais casos os arquivos devero ser
vistos como seqncias de caracteres, uma vez que a linguagem natural no pode, normalmente, ser
reduzida para a forma de termos.
8.2 PROCESSAMENTO DE ARQUIVOS DE TERMOS
8.2.1 READ & WRITE
O predicado pr-definido read/1 usado para a leitura de termos a partir da fonte de entrada corrente.
O objetivo
read(X)
ir ocasionar a leitura do prximo termo T que ser unificado com X. Se X uma varivel, ento,
como resultado da leitura, X ser instanciada com T. Se a unificao no for possvel, ento o objeti-
vo read(X) ir falhar. O predicado read/1 determinstico, significando que, em caso de falha, no
haver backtracking para a leitura de outro termo. cada termo, no arquivo de entrada, deve ser seguido
por um ponto e um espao ou "carriage-return". Se read(X) executado sobre o final do arquivo de
entrada, ento a varivel X ser instanciada com o termo "end_of_file".
O predicado pr-definido write/1 fornece a sada de um termo. Assim o objetivo write(X) ir ocasio-
nar a escrita do termo X sobre a fonte de entrada corrente. X ser escrito com a mesma forma sinttica
padro utilizada pelo Prolog na apresentao de termos. Um recurso muito til do Prolog que o pre-
dicado write/1 "sabe" apresentar qualquer termo, independente de sua complexidade.
H ainda dois predicados adicionais para a formatao da sada. Eles so usados para inserir espaos e
linhas na fonte de sada. O objetivo tab(N) ir ocasionar a sada de "N" espaos. O predicado nl/0
(sem argumentos) ir ocasionar o incio de uma nova linha. os seguintes exemplos ilustram o uso dos
procedimentos estudados. Vamos assumir que temos um procedimento que computa o cubo de um
nmero dado:
cubo(N, C) :- C is N*N*N.
Suponha que desejamos empreg-lo para calcular os cubos de uma seqncia de nmeros. Isso pode
ser obtido por meio de uma seqncia de questes:
?-cubo(2, X).
X=8
?-cubo(5, Y).
Y=125
?-cubo(12, Z).
Z=1728
Aqui, para cada nmero necessrio formular um objetivo completo. Vamos agora modificar o pro-
grama de forma a "interiorizar" a ao, tornando mais suave o interface com o usurio. O programa
agora ir manter-se lendo um nmero e apresentando o seu cubo at que a constante "fim" seja lida da
fonte de entrada.
cubo :-
read(X), processa(X).
74
processa(fim) :- !.
processa(N) :-
C is N*N*N,
write(C),
cubo.
Esse um programa cujo significado declarativo difcil de formular, entretanto, a sua interpretao
operacional direta: "Para executar cubo/0, primeiro leia X e depois processe-o. Se X=fim, ento,
tudo j foi feito. Seno, calcule o cubo de X, escreva-o e chame recursivamente o procedimento
cubo/0 para o processamento de mais valores. Por exemplo:
?-cubo.
2.
8
5.
25
12.
1728
fim.
sim
Os nmeros 2, 5 e 12 (seguidos de "." e "enter") so digitados pelo usurio no teclado do terminal. Os
outros nmeros correspondem a sada do programa. Note que aps cada nmero digitado pelo usurio
deve haver um ponto, que seguido de um carriage-return (cr, enter, return ou , na maioria dos termi-
nais), sinaliza ao sistema o final de um termo.
O procedimento cubo/0 conduz ento a interao entre o usurio e o programa. Em tais casos, nor-
malmente desejvel que o programa, antes de ler um novo valor, sinalize ao usurio que est pronto a
receber uma nova informao, e que talvez ainda torne explcito o tipo de informao que esperado.
Isso normalmente realizado pelo envio de um sinal "prompt" - de "prontido" - ao usurio, antes de
efetua a leitura. O procedimento cubo/0 seria modificado para algo como:
cubo :-
write('Prximo valor: '),
read(X),
processa(X).
processa(fim) :- !.
processa(N) :-
C is N*N*N,
write('O cubo de '), write(N), write(' '),
write(C), nl, cubo.
Um dilogo com essa nova verso do programa seria:
?-cubo.
Prximo valor: 5.
O cubo de 5 125
Prximo valor: 8.
O cubo de 8 512
Prximo valor: 12.
O cubo de 12 1728
Prximo valor: fim.
sim
Dependendo da implementao, uma requisio adicional (como "flush/0" para o descarregamento
dos buffers de i/o) pode ser necessria aps o comando de escrita do prompt para for-lo a aparecer
na tela antes da leitura
8.2.2 ESCREVENDO LISTAS
Paralelamente ao formato padro que o Prolog possui para listas, h ainda diversas outras formas para
a apresentao de listas que podem ser vantajosas em certos casos. vamos definir o procedimento
escreveLista(L), que escreve a lista L na fonte de sada corrente, de modo que cada elemento de L seja
escrito em uma nova linha:
75
escreveLista([]).
escreveLista([X | L]) :-
write(X), nl, escreveLista(L).
Se tivermos uma lista de listas, uma forma natural de sada escrever os elementos de cada lista em
uma linha. Um exemplo :
?-escreveLista2([[a, b, c], [d, e, f], [g, h, i]]).
a b c
d e f
g h i
sim
O procedimento escreveLista2/1 que permite obter essa sada :
escreveLista2([]).
escreveLista2([L | LL]) :-
imprime(L), nl, escreveLista2(LL).
imprime([]).
imprime([X | L]) :-
write(X), tab(1), imprime(L).
Uma lista de nmeros inteiros pode algumas vezes ser convenientemente apresentada sob a forma de
um grfico de barras. O procedimento barras(L) ir escrever uma lista nessa forma. Um exemplo do
seu uso seria:
?-barras([6, 7, 9, 12]).

sim
escreveFam(famlia(Pai, Me, Filhos)) :-
nl, nl, write('Pais:'), nl,
escrevePes(Pai), nl, escrevePes(Me), nl,
write('Filhos:'), nl,
escrevePesList(Filhos).
escrevePes(pessoa(Nome, SNome, dat(D,M,A), Trab)) :-
tab(10), write(Nome), tab(1), write(SNome),
write(', nasc: '),
write(D), write('/'), write(M), write('/'), write(A),
write(','), escreveTrab(Trab).
escrevePesList([]).
escrevePesList([P | L]) :-
escrevePes(P), nl, escrevePesList(L).
escreveTrab(nt) :-
write('no trabalha').
escreveTrab(trab(Emp, Sal)) :-
write('trab: '), write(Emp), write(', '),
write('sal: '), write(Sal).
Figura 8.2 Um programa para a formatao do termo "famlia"
O procedimento barras/1 pode ser definido da seguinte maneira, assumindo que a representao ''
seja vlida no Prolog utilizado:
barras([]).
barras([N | L]) :-
quadrinho(N), nl, barras(L).
quadrinho(N) :-
N>0,
write(' '), N1 is N-1,quadrinho(N1).
quadrinho(N) :-
N=<0, !.
76
8.2.3 FORMATAO DE TERMOS
Vamos considerar novamente a representao sob a forma de termos usada para definir famlias, dis-
cutida na seo 7.1. Se uma varivel F for instanciada com o termo cuja estrutura mostrada na figura
7.1, o objetivo write(F) ir ocasionar a sada do termo correspondente no formato padro do Prolog.
Alguma coisa como:
famlia(pessoa(ari, pl, data(17,05,65), trab(ibn,1500)),
pessoa(ana, pl, data(06,11,58), trab(rbz,1100)),
[pessoa(ada, pl, data(18,02,91), nt)])
O termo acima contm, sem dvida, toda a informao, entretanto sob uma forma bastante confusa,
tornando difcil seguir as partes da informao que formam as unidades semnticas. Iramos, certa-
mente, preferir que a informao fosse apresentada de outra maneira, por exemplo, na forma abaixo:
Pais:
ari pl, nasc: 16/05/65, trab: ibn, sal: 1500
ana pl, nasc: 06/11/68, trab: rbz, sal: 1100
Filhos:
ada pl, nasc: 18/02/91, no trabalha.
Tal formato pode ser obtido por meio do procedimento escreveFam/1 mostrado na Figura 8.2.
8.2.4 PROCESSAMENTO DE ARQUIVOS DE TERMOS
Uma tpica seqncia de objetivos para processar completamente um arquivo "A" se pareceria com o
seguinte:
... see(A), processaArq, see(user), ...
Aqui processaArq/0 um procedimento para ler e processar cada termo em A, um aps o outro, at
que o fim do arquivo seja encontrado. Um esquema tpico para processaArq o seguinte:
processaArq :-
read(Termo), processa(Termo).
processa(end_of_file) :- !.
processa(Termo) :-
trata(Termo), processaArq.
Aqui o procedimento trata/1 representa qualquer coisa que se deseje fazer com cada um dos termos
presentes no arquivo. Um exemplo poderia ser um procedimento para apresentar no terminal cada um
dos termos do arquivo, juntamente com o seu respectivo nmero de ordem. Vamos chamar tal proce-
dimento mostraArq(N), onde N um argumento adicional para contar os termos lidos.
mostraArq(N) :-
read(Termo), mostra(1, Termo).
mostra(_, end_of_file) :- !.
mostra(N, Termo) :-
write(N), tab(2), write(Termo),
N1 is N+1,
mostraArq(N1).
outro exemplo de utilizao do esquema dado para o processamento de arquivos de termos o se-
guinte: Temos um arquivo denominado "arq1" que contm termos na forma:
item(Nro, Descrio, Preo, Fornecedor)
Cada termo descreve uma entrada num catlogo de itens. Desejamos produzir um outro arquivo que
contenha somente os itens fornecidos por um determinado fornecedor. Como o fornecedor nesse novo
arquivo ser sempre o mesmo, o seu nome somente precisa ser escrito no incio do arquivo, sendo
omitido nos demais termos. Denominaremos tal procedimento de
fazArq(Fornecedor)
Por exemplo, se o catlogo original armazenado em arq1 e desejamos produzir um arquivo arq2 com
todos os artigos fornecidos por 'Palmeira & Cia", ento usaremos o procedimento fazArq/1 da se-
77
guinte maneira:
..., see(arq1),tell(arq2),fazArq('Palmeira & Cia'),see(user),tell(user), ...
O procedimento fazArq/1 apresentado na Figura 8.3
fazArq(F) :-
write(F), write('.'), nl, fazResto(F).
fazResto(F) :-
read(Item), processa(Item, F).
processa(end_of_file, _) :- !.
processa(item(N, D, P, F), F) :-
!, write(item(N, D, P)), write('.'), nl, fazResto(F).
processa(_, F) :-
fazResto(F).
Figura 8.3 Processando um arquivo de itens
Note que no programa acima, o predicado processa/2 grava um ponto aps cada termo escrito em
arq2, de modo a possibilitar leituras posteriores desse arquivo por meio do comando read/1.
8.3 PROCESSAMENTO DE CARACTERES
Um caracter escrito na fonte de sada corrente por meio do objetivo:
put(C)
onde C o cdigo ASCII (um nmero entre 0 e 255) do caracter a ser escrito. Por exemplo, a consul-
ta:
?-put(65), put(66), put(67).
produz a sada:
ABC
uma vez que 65 o cdigo ASCII de 'A', 66 de 'B' e 67 de 'C'. Por sua vez um caracter pode ser lido a
partir da fonte de entradacorrente por meio do objetivo:
get0(C)
que ocasiona a leitura do caracter corrente e torna a varivel C instanciada para com o cdigo ASCII
deste caracter. Uma variao do predicado get0/1 o get/1, que utilizado para a leitura apenas de
caracteres imprimveis, saltando sobre todos os caracteres no-imprimveis, particularmente espaos
em branco. Como um exemplo do uso de predicados que transferem caracteres, vamos definir um
procedimento comprime/0 para ler uma sentena da fonte de entrada corrente e apresentar essa sen-
tena reformatada, de forma que mltiplos espaos em branco entre as palavras sejam substitudos por
um nico espao em branco (cdigo ASCII = 32). Para simplificar, vamos assumir que toda sentena
de entrada processada pelo procedimento comprime/0 termina com um ponto final (cdigo ASCII =
46) e que as palavras estejam separadas por um ou mais espaos em branco e nenhum outro caracter.
Uma entrada aceitvel seria:
Genialidade 1% de inspirao e 99% de transpirao.
para a qual o procedimento comprime/0 devolveria:
Genialidade 1% de inspirao e 99% de transpirao.
O procedimento comprime/0 ter uma estrutura similar aos procedimentos para processamento de
arquivos estudados nas sees anteriores. Inicialmente ele vai ler o primeiro caracter e envi-lo sa-
da e ento completar o processo, dependendo do caracter que for lido. A excluso mtua entre as trs
alternativas obtida por meio de cuts:
comprime :-
get0(C), put(C), continua(C).
78
continua(46) :- !.
continua(32) :-
!, get(C), put(C), continua(C).
continua(_) :-
comprime.
8.4 CONVERSO DE TERMOS
Frequentemente deseja-se trabalhar com informaes que foram lidas sob a forma de caracteres, con-
vertidas em termos como representao interna para processamento de entrada e sada. H um predi-
cado pr-definido, name/2, que pode ser usado com essa finalidade, relacionando os tomos com o seu
cdigo ASCII. Assim, name(X, L) verdadeiro, se L a lista dos cdigos dos caracteres em A. Por
exemplo, a assertiva abaixo verdadeira:
name(zx232, [122, 120, 50, 51, 50])
H dois usos tpicos para o predicado name/2:
Decompor um termo dado em seus caracteres, e
Dada uma lista de caracteres, converte-la em um termo.
Um exemplo do primeiro tipo de aplicao seria a decomposio de tomos em tomos menores, com
tamanho pr-definido. Suponhamos que recebemos, de alguma fonte de entrada, tomos de tamanho
fixo de 13 caracteres, dos quais os oito primeiros correspondem ao CEP, os dois seguintes unidade
da federao (UF) e os trs ltimos sigla internacional de cidade. Por exemplo:
90120040rspoa e 70605220dfbsb
e desejamos, para fins de processamento, separ-los nos sub-tomos:
90120040 rs poa e 70605220 df bsb
O predicado separa/4, abaixo, obtm o resultado desejado:
separa(A, S1, S2, S3) :-
name(A, L),
conc([S1, S2, S3], [], L),
tam(S1, 8), !,
tam(S2, 2), !,
tam(S3, 3).
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
tam([], 0).
tam([_|R], N) :-
tam(R, N1), N1 is N+1.
O prximo exemplo ilustra o uso da combinao de caracteres em tomos. Definiremos um predicado,
fazFrase(Lista) que l uma sentena em linguagem natural e instancia Lista com cada palavra da sen-
tena representada por um tomo. Por exemplo, se a entrada fosse a seguinte frase, atribuda a Albert
Einstein dirigindo-se a Sigmund Freud:
"No matter what mind is and never mind what matter is."
o objetivo fazFrase(Lista) ocasionaria a seguinte instanciao:
Lista = ['No',matter,what,mind,is,and,never,mind,what,matter,is]
para simplificar, assume-se que cada sentena termina com um ponto final e que no h smbolos de
pontuao na sentena. O programa completo mostrado na Figura 8.4. O procedimento fazFrase/1 l
o caracter corrente, C, e ento transmite esse caracter ao procedimento fazResto para completar o
servio.
fazFrase(Lista) :-
get0(C), fazResto(C, Lista).
79
fazResto(46, []) :- !.
fazResto(32, Lista) :-
!, fazFrase(Lista).
fazResto(Let, [Pal | Lista]) :-
fazLetras(Let, Lets, Prox),
name(Pal, Lets),
fazResto(Prox, Lista).
fazLetras(46, [], 46) :- !.
fazLetras(32, [], 32) :- !.
fazLetras(Let, [Let | Lets], Prox) :-
get0(C), fazLetras(C, Lets, Prox).
Figura 8.4: Transformando uma sentena em uma lista de palavras
O procedimento fazResto/2, na Figura 8.4, precisa considerar trs casos:
C um ponto (ASCII=46). Ento tudo j foi lido;
C um branco (ASCII=32). Ento deve ser ignorado;
C uma letra. Primeiro ler a palavra Pal, que comea com C, e depois, ppor meio de fazFrase/1,
ler o resto da sentena, produzindo Lista. O resultado cumulativo [Pal | Lista].
O procedimento que l os caracteres de uma palavra :
fazLetra(Let, Lets, Prox)
onde:
(1) Let a letra corrente (j lida) da palavra que est sendo processada,
(2) Lets a lista de letras (comeando com Let), at o final da palavra, e
(3) Prox o caracter de entrada que imediatamente segue a palavra lida, podendo ser um branco ou
um ponto.
O programa fazFrase/1 pode ser usado para o processamento de textos em linguagem natural. As sen-
tenas representadas como listas de palavras encontram-se em uma forma adequada para processa-
mento adicional em Prolog. Um exemplo simples seria o tratamento de certas palavras do texto. Uma
tarefa muito mais difcil seria "entender" a sentena, isto , extrair dela o seu significado, representa-
do por algum formalismo. Esta uma importante rea de pesquisa em inteligncia artificial.
8.5 LEITURA DE PROGRAMAS
possvel carregar programas no sistema Prolog por meio de dois predicados pr-definidos: consult/1
e reconsult/1. Diz-se ao Prolog para ler um programa que esteja contido em um arquivo "progra-
ma.log" da seguinte maneira:
?-consult('programa.log').
cujo efeito a leitura de todas as clusulas em programa.log de modo que estas possam ser usadas
pelo sistema para responder as consultas que se seguirem. Se um outro arquivo for "consultado" du-
rante a mesma seo, as clusulas presentes nesse novo arquivo sero simplesmente adicionadas ao
final do conjunto de clusulas corrente. No necessrio, entretanto, gravar nosso programa em um
arquivo para depois carreg-lo no sistema. Ao invs de ler um arquivo o Prolog pode tambm aceitar o
nosso programa diretamente do terminal, que corresponde ao pseudo-arquivo "user". Obtemos isso
por meio de:
?-consult(user).
que leva o Prolog a aceitar clusulas digitadas diretamente no teclado do terminal.
Uma notao mais curta para a carga de programas consiste em colocar os arquivos que devem ser
80
lidos em uma lista e declar-la como objetivo. Por exemplo:
?-[prog1, prog2, prog3].
que corresponde exatamente ao obtido por:
?-consult(prog1), consult(prog2), consult(prog3).
O predicado pr-definido reconsult/1 opera de maneira semelhante ao consult/1. Um objetivo
?-reconsult(programa).
ter o mesmo efeito de consult com uma exceo: se houver clusulas em "programa" sobre alguma
relao j definida no sistema, a definio anterior ser substituda pelas novas clusulas presentes em
"programa". A diferena entre consult/1 e reconsult/1 que o primeiro sempre adiciona as novas clu-
sulas, ao passo que o segundo redefine as relaes previamente definidas, sem afetar, entretanto, as
relaes para as quais no existem clusulas em "programa".
RESUMO
Entradas e sadas (alm das efetuadas em consultas ao programa) so executadas por meio de
predicados pr-definidos;
Os arquivos so sequenciais. H uma fonte de entrada corrente e uma fonte de sada corrente. O
terminal do usurio tratado como um arquivo denominado "user".
A mudana entre fontes de entrada e de sada correntes /e efetuada pelos predicados:
see(A): A se torna a fonte de entrada corrente
tell(A): A se torna a fonte de sada corrente
seen: Fecha a fonte de entrada corrente
told: Fecha a fonte de sada corrente
Os arquivos so lidos ou gravados de dois modos diferentes: como uma seqncia de caracteres
ou como uma sequncia de termos;
Predicados pr-definidos para a leitura e escrita de termos e caracteres so:
read(Termo)
write(Termo)
put(Cdigo)
get0(Cdigo)
get(Cdigo)
Dois predicados utilizados para formatao so:
nl
tab(N)
O procedimento name(tomo, Lista) decompe e constri tomos. Lista a lista dos cdigos
ASCII dos caracteres em tomo.
EXERCCIOS
8.1 Seja arq um arquivo de termos. Defina um procedimento achaTermo(Termo) que apresenta no
terminal do usurio o primeiro termo em arq que unifica com Termo.
8.2 Seja arq um arquivo de termos. Escreva um procedimento achaTodos(Termo) que apresenta no
terminal todos os termos em arq que unificam com Termo.
8.3 Defina a relao comeaCom(tomo, Caracter), para verificar se tomo inicia com o caracter
Caracter.
8.4 Escreva um procedimento acha(PalavraChave, Sentena) que ir, a cada vez que for chamado,
localizar uma sentena na fonte de entrada corrente que contenha a palavra chave dada. A sen-
81
tena deve ser fornecida em sua forma original, representada como uma seqncia de caracteres
ou como um tomo. O programa fazFrase/2 apresentado neste captulo pode ser adequadamente
modificado para atender as necessidades deste exerccio.
8.5 Escreva um programa relatrio/0 para ler um arquivo de termos na forma cliente(Nome, Endere-
o, Telefone) e produzir um relatrio formatado da seguinte maneira:
NRO CLIENTE ENDEREO TELEFONE
001 XXX... XXX... XXX....
002 XXX... XXX... XXX...
..... ..... ..... .....
8.6 Escreva um programa, plural(Palavra, Plural), para a formao do plural de palavras em portu-
gues. Crie para isso uma base de regras de formao do plural de palavras. O resultado esperado
, por exemplo:
?-plural(pssaro, X).
X=pssaros
82
9. PREDICADOS EXTRALGICOS
Todas as implementaes Prolog oferecem, em maior ou menor quantidade, um certo nmero de pre-
dicados pr-definidos orientados a execuo de rotinas que, ou so necessrias com muita freqncia,
ou so de difcil programao, ou se destinam a um domnio particular realado pela implementao,
ou por todas essas razes em diferentes propores. No presente captulo se introduz alguns desses
predicados, que facilitam muito a construo de programas interativos e orientados a aplicaes con-
cretas.
9.1 TIPOS DE TERMOS
Os termos Prolog podem assumir os mais diversos aspectos, desde simples constantes at estruturas
complexas altamente elaboradas. Se um termo uma varivel, ento esta pode ou no estar instancia-
da em algum momento da execuo do programa. Alm disso, se estiver instanciada, seu valor pode
ser uma constante, uma estrutura, etc. Algumas vezes pode ser de utilidade para o programador identi-
ficar de que tipo esse valor. Por exemplo, podemos querer adicionar os valores de duas variveis, X
e Y, por meio de:
Z is X + Y
Antes desse objetivo ser executado, X e Y devem ser instanciados com valores inteiros. Se no h
certeza de que tal instanciao ocorreu, ento deve-se fazer tal verificao antes de executar a oprera-
o aritmtica envolvida.
Com essa finalidade podemos utilizar o predicado pr-definido integer(X), que verdadeiro se X esti-
ver instanciada com um varlor inteiro. O objetivo de adicionar X e Y ento pode ser protegido da
seguinte maneira, garantindo a validade dos operandos:
..., integer(X), integer(Y), Z is X + Y, ...
`Se X e Y no estiverem ambas instanciadas com valores inteiros, ento a operao aritmtica que se
segue ao teste no ser realizada. Os predicados pr-definidos para a classificao de dados comuns a
maioria das implementaes so os seguintes:
Predicado Descrio
atom(X) bem sucedido se X uma constante textual (tomo).
integer(X) bem sucedido se X um nmero inteiro.
float(X) bem sucedido se X um nmero em ponto flutuante.
number(X) bem sucedido se X um nmero.
string(X) bem sucedido se X um string.
atomic(X) bem sucedido se X do tipo atmico.
var(X) bem sucedido se X uma varivel no-instanciada.
nonvar(X) bem-sucedido se X no uma varivel ou se X uma varivel instanciada.
O programa classifica/1, apresentado na figura abaixo, ilustra o emprego de tais predicados.
O programa classifica/1 (Figura 9.1) ir reconhecer o tipo do seu argumento, informando-o ao usu-
rio. Em particular, se o dado do tipo atmico, o subtipo tambm informado, como ilustrado abai-
xo:
83
?-X=1, classifica(X).
Tipo Atmico
---> Numero Inteiro
?-X=[], classifica(X).
Tipo Atmico
---> Lista Vazia
?-X=tio(jos), classifica(X).
Termo Estruturado
classifica(X) :-
var(X), !, nl, write('Varivel No-instanciada').
classifica(X) :-
atomic(X), !, nl, write('Tipo Atmico:'),
tipoAtomico(X).
classifica([_|_]) :-
!, nl, write('Lista').
classifica(X) :-
nl, write('Termo Estruturado').
tipoAtomico([]) :-
!, nl, tab(5), write('---> Lista Vazia').
tipoAtomico(X) :-
atom(X), !, nl, tab(5), write('---> tomo').
tipoAtomico(X) :-
integer(X), !, nl, tab(5),
write('---> Nmero Inteiro').
tipoAtomico(X) :-
float(X), !, nl, tab(5),
write('---> Nmero em Ponto Flutuante').
tipoAtomico(X) :-
string(X), !, nl, tab(5), write('---> String').
Figura 9.1 Programa para classificar tipos de dados.
Vamos supor agora que se deseje contar quantas vezes um determinado tomo ocorre em uma lista de
objetos dada. Com esse propsito se definir o procedimento
conta(A, L, N)
onde A o tomo, L a lista e N o nmero de vezes que A ocorre em L. Uma primeira tentativa de
definir conta/3 seria:
conta(_, [], 0).
conta(A, [A | L], N) :-
!, conta(A, L, N1), N is N1+1.
conta(A, [_ | L], N) :-
conta(A, L, N).
Algumas tentativas de utilizao de tal programa so:
?-conta(a, [a, b, a, a], N).
N=3
?-conta(a, [a, b, X, Y], Na).
X=a Y=a Na=3
?-conta(b, [a, b, X, Y], Nb).
X=b Y=b Nb=3
?-L=[a, b, X, Y], conta(a, L, Na), conta(b, L, Nb).
X=a Y=a Na=3 Nb=1
Neste ltimo exemplo, X e Y foram ambas instanciadas com "a", e portanto obtivemos Nb=1 somente.
No era isso, entretanto que se tinha em mente na construo do procedimento conta/3. Na verdade o
que se queria era o nmero real de ocorrncias de um dado tomo e no o nmero de termos capazes
de unificar com esse tomo. De acordo com essa definio mais precisa da relao conta/3, devemos
verificar se a cabea da lista um tomo. A nova verso da relao conta a seguinte:
conta(_, [], 0).
conta(A, [B | L], N) :-
atom(B), A=B, !, conta(A, L, N1), N is N1+1.
conta(A, [_ | L], N) :-
84
conta(A, L, N).
9.2 CONSTRUO E DECOMPOSIO DE TERMOS
H trs predicados pr-definidos para a decomposio de termos e construo de novos termos: func-
tor/3, arg/3 e =../2. Estudaremos primeiro o =../2, tambm referido como "univ", que definido como
um operador infixo. O objetivo
Termo =.. L
bem-sucedido se L uma lista contendo como primeiro elemento o functor principal de Termo, se-
guido pelos seus argumentos. Os seguintes exemplos do uma idia do seu funcionamento:
?-f(a, b) =.. L.
L=[f, a, b]
?-T =.. [retngulo, 3, 5].
T=retngulo(3, 5)
?-Z =.. [p, X, f(X, Y)].
Z=p(X, f(X, Y))
Para melhor ilustrar a utilidade do operador =../2, vamos considerar um programa que manipula figu-
ras geomtricas como quadrados, retngulos, tringulos, crculos, etc. Estas entidades podem ser re-
presentadas por meio de termos tais que o functor principal indica o tipo de figura e os argumentos
especificam o tamanho da figura, como em:
quadrado(Lado)
tringulo(Lado1, Lado2, Lado3)
crculo(Raio)
Uma operao sobre tais figuras poderia ser a ampliao das mesmas. Pode-se implement-la como
uma relao de trs argumentos
amplia(Fig, Fator, Fig1)
onde Fig e Fig1so figuras geomtricas do mesmo tipo (mesmo functor) e os parmetros de Fig1 so
os mesmos de Fig, multiplicados por Fator. Para maior simplicidade assumiremos que os parmetros
de Fig so previamente conhecidos, isto , instanciados com nmeros, o mesmo ocorrendo com Fator.
Uma maneira de programar a relao amplia/3 a seguinte:
amplia(quadrado(A), F, quadrado(A1)) :-
A1 is F * A.
amplia(crculo(R), F, circulo(R1)) :-
R1 is F * R.
amplia(retngulo(A, B), F, retngulo(A1, B1)) :-
A1 is F * A, B1 is F * B.
...
Esse procedimento funciona, mas um tanto grosseiro no caso em que h muitos tipos diferentes de
figuras. necessrio prever todos os tipos de figuras que podem acontecer, empregando uma clusula
para cada tipo, apesar de todos dizerem essencialmente a mesma coisa: tome os parmetros da figura
original e multiplique-os pelo fator de ampliao formando uma figura do mesmo tipo com os novos
parmetros. Uma tentativa (mal-sucedida) de manipular pelo menos todas as figuras de um nico ar-
gumento seria:
amplia(Tipo(Arg), F, Tipo(Arg1)) :-
Arg1 is Arg * F.
Entretanto, no permitido representar um functor em Prolog diretamente por meio de uma varivel,
ou seja, functores devem ser sempre tomos, portanto a varivel Tipo no seria aceita pela sintaxe da
linguagem. O mtodo correto utilizar o predicado =../2. Assim a relao amplia/3, genrica, pode ser
escrita como se segue:
amplia(Fig, F, Fig1) :-
Fig =.. [Tipo | Parmetros],
multLista(Parmetros, F, NovosParmetros),
Fig1 =.. [Tipo | NovosParmetros].
multLista([], _, []).
85
multLista([X | L], F, [X1 | L1]) :-
X1 is F*X, multLista(L, F, L1).
Os termos construdos com o predicado =../2 podem tambm ser executados como objetivos. A vanta-
gem disto que o prprio programa pode, durante a execuo gerar e executar objetivos. Uma se-
qncia de objetivos ilustrando esse efeito poderia ser a seguinte:
...
obtenha(Functor),
compute(ListaDeArgumentos),
Obj =.. [Functor | ListaDeArgumentos],
Obj, ...
Aqui, obtenha/1 e compute/1correspondem a procedimentos definidos pelo usurio para obteros com-
ponentes do objetivo a ser construdo. O objetivo formado por meio do predicado =../2 e disparado
para execuo por meio da varivel que o nomeia, Obj.
Algumas implementaes da linguagem Prolog podem requerer que todos os objetivos que aparecem
no programa sejam tomos ou uma estrutura com um tomo como functor principal, de forma que
uma varivel, independentemente de sua eventual instanciao, pode no ser sintaticamente aceita
como um objetivo. Esse problema contornado por meio de outro predicado pr-definido, call/1, cujo
argumento um objetivo a ser executado. Assim o exemplo dado acima poderia ser reescrito como:
...
Obj =.. [Functor | ListaDeArgumentos]
call(Obj).
s vezes pode-se desejar extrair de um termo apenas o seu functor principal, ou um de seus argu-
mentos. Em tais casos pode-se, naturalmente, empregar o predicado =../2, entretanto, pode ser mais
prtico e eficiente usar um dos outros dois predicados pr-definidos para a manipulao de termos:
functor/3 e arg/3, cujo significado o seguinte:
functor(Termo, Functor, Aridade)
verdadeiro se Functor o functor principal de Termo e Aridade o seu nmero de argumentos, ao
passo que
arg(N, Termo, Argumento)
verdadeiro se Argumento o N-simo argumento em Termo, assumindo que os argumentos so
numerados da esquerda para direita iniciando em 1. Os seguintes exemplos servem como ilustrao:
?-functor(teste(f(X), X, t), Functor, Aridade).
Functor=teste Aridade=3
?-arg(2, teste(X, t(a), t(b)), Argumento).
Argumento=t(a)
?-functor(D, data, 3), arg(1, D, 5), arg(2, D, abril), arg(3, D, 1994).
D=data(5, abril, 1994)
Esse ltimo exemplo mostra uma aplicao especial do predicado functor/3. O objetivo functor(D,
data, 3) produz em D um termo "geral" cujo functor principal "data", com 3 argumentos. O termo
geral no sentido em que os trs argumentos so variveis no-instanciadas geradas pelo sistema Pro-
log. Por exemplo:
D=data(_02e, _02f, _030)
Essas trs variveis so ento instanciadas como no exemplo acima, por meio dos trs objetivos arg/3.
Relacionado a esse conjunto de predicados est o predicado name/2, para a construo e decomposi-
o de tomos, introduzido no captulo anterior. Seu significado repetido aqui para manter completa
a seo:
name(tomo, Lista)
verdadeiro se Lista a lista dos cdigos ASCII correspondentes aos caracteres do tomo A.
9.3 EQUIVALNCIAS E DESIGUALDADES
86
At o momento, trs "tipos de igualdade" foram estudados, iniciando pela baseada na unificao, re-
presentada por:
X = Y
que verdadeira se X Y unificam. Um outro tipo de igualdade
X is Expresso
que verdadeira se X unifica com o valor da expresso aritmtica Expresso. Tem-se tambem:
Expreso1 =:= Expresso2
que verdadeira se os os valores das expresses aritmticas Expresso1 e Expresso2 so iguais. Se,
ao contrrio as expresses possuem valor diferente, escreve-se:
Expresso1 =\= Expresso2
Algumas vezes poder ser necessrio um tipo mais estrito de igualdade: a igualdade literal entre dois
termos. Esse tipo de igualdade implementado por meio de um predicado pr-definido escrito como o
operador infixo "==", de modo que
Termo1 == Termo2
verdadeira se os termos Termo1 e Termo2 so idnticos, isto , possuem exatamente a mesma es-
trutura e todos os componentes correspondentes so os mesmos. Em particular, os nomes das vari-
veis devem tambm ser os mesmos. A relao complementar a no-identidade, escrita como:
Termo1 \== Termo2
Os exemplos abaixo abordam o uso de tais operadores:
?-f(a, b) == f(a, b).
sim
?-f(a, b) == f(a, X).
no
?-f(a, X) == f(a, Y).
no
?-X \== Y.
sim
?-t(X, f(a, Y)) \== t(X, f(a, Y)).
no
9.4 PROGRAMAS OU BASES DE DADOS?
De acordo com o modelo relacional, uma base de dados a especificao de um conjunto de relaes.
Sob tal prisma, um programa Prolog pode ser visto como uma base de dados: a especificao das rela-
es parcialmente implcita (regras) e parcialmente explcita (fatos). Alm disso existem predicados
pr-definidos que tornam possvel a atualizao da base de dados durante a execuo do programa.
Isso feito em tempo de execuo, pela adio ou remoo de clusulas do programa. Os predicados
que servem a tais propsitos so assert/1, asserta/1, assertz/1 e retract/1. Um objetivo como:
assert(C)
sempre bem sucedido e, como efeito colateral, ocasiona a adio da clusula C na base de dados.
Por outro lado um objetivo
retract(C)
faz o oposto, isto , apaga uma clusula que unifica com C da base de dados. O dilogo abaixo exem-
plifica esses dois predicados:
?-crise.
no
?-assert(crise).
sim
87
?-crise.
sim
?-retract(crise).
sim
?-crise.
no
As clusulas inseridas por meio do predicado assert/1, atuam exatamente como se fossem parte do
programa original. O seguinte exemplo ilustra o uso de assert/1 e retract/1 como um mtodo para
controlar situaes que se modificam ao longo do tempo. Vamos assumir o programa abaixo, sobre as
condies do tempo:
bom :-
sol, not chuva.
instvel :-
sol, chuva.
deprimente :-
chuva, neblina.
chuva.
neblina.
O dilogo a seguir mostra como a base de dados pode ir sendo gradualmente atualizada:
?-bom.
no
?-deprimente.
sim.
?-retract(neblina).
sim
?-deprimente.
no
?-assert(sol)
sim
?-instvel.
sim
?-retract(chuva).
sim
?-bom
sim
Qualquer tipo de clusula pode ser objeto dos predicados assert/1 ou retract/1. No prximo exemplo
mostraremos que retract/1 tambm no-determinstico: um conjunto completo de clusulas pode ser
removido, por meio do mecanismo de bactracking, atravs de um nico objetivo retract/1. Vamos
assumir um programa com os seguintes fatos:
veloz(senna).
veloz(prost).
meiaBoca(alesi).
meiaBoca(barrichello).
lento(katayama).
lento(moreno).
Podemos adicionar uma regra ao programa da seguinte maneira:
?-assert( (vence(X, Y) :- veloz(X), not veloz(Y)) ).
sim
?-vence(A, B).
A=senna B=alesi;
A=senna B=barrichello;
A=senna B=katayama;
A=senna B=moreno;
A=prost B=alesi;
A=prost B=barrichello;
A=prost B=katayama;
A=prost B=moreno;
88
no
Note que quando uma regra inserida na base de dados, por meio do predicado assert, as regras sint-
ticas do Prolog exigem que esta seja fornecida entre parnteses.
Na introduo de uma clusula, podemos desejar especificar a posio na qual a clusula deve ser
inserida na base de dados. Os predicados asserta/1 e assertz/1 permitem controlar a posio de inser-
o. O objetivo
asserta(C)
introduz a clusula C no incio da base de dados, enquanto que o objetivo
assertz(C)
adiciona a clusula C no final da base de dados. O seguinte exemplo ilustra esses efeitos:
?-assert(p(a)), assertz(p(b)), asserta(p(c)).
sim
?-p(X).
X=c;
X=a;
X=b;
no
H uma relao entre consult/1 e assertz/1. "Consultar" um arquivo pode ser definido em termos de
assertz/1 da seguinte maneira: para "consultar" um arquivo, ler cada um dos seus termos (clusulas) e
inser-los no final da base de dados:
consult(X) :-
see(X), transfere(C), see(user).
transfere(end_of_file) :- !.
transfere(C) :-
read(C), assertz(C), transfere(C1).
J uma aplicao til do predicado asserta/1 armazenar respostas j computadas para consultas for-
muladas ao programa. Por exemplo, vamos considerar que o predicado
resolve(Problema, Soluo)
esteja definido. Podemos agora formular alguma consulta e requerer que a resposta seja lembrada para
consultas futuras:
?-resolve(prob1, Sol), asserta(resolve(prob1, Sol)).
Se o primeiro objetivo acima bem-sucedido, ento a resposta(Soluo) armazenada e utilizada,
como qualquer outra clusula, na resposta a questes futuras. A vantagem de memorizar as respostas
que uma consulta posterior que unifique com "prob1" ser respondida muito mais rapidamente. O
resultado obtido agora pela recuperao de um fato, no sendo necessrias computaes adicionais
que possivelmente consumiriam muito mais tempo.
Uma extenso dessa idia a utilizao do assert para gerar todas as solues possveis na forma de
uma tabela de fatos. Por exemplo, podemos gerar uma tabela com os produtos de todos os pares de
inteiros de 0 a 9 da seguinte maneira: geramos um par de inteiros, X e Y, computamos Z is X*Y, inse-
rimos os trs nmeros como uma linha da tabela de produtos e ento foramos a falha do procedi-
mento que, por meio de backtracking, ir gerar a tabela completa. O procedimento tabMult/0, abaixo,
implementa essa idia:
tabMult :-
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
membro(X, L), membro(Y, L),
Z is X*Y, assert(produto(X, Y, Z)), fail.
tabMult.
O efeito colateral da execuo de tabMult/0 adicionar a correspondente tabela de multiplicao
base de dados. Depois disso, podemos perguntar, por exemplo, que pares da tabela resultam em 8:
89
?-produto(A, B, 8).
A=1 B=8;
A=2 B=4;
A=4 B=2;
A=8 B=1;
no
Uma advertncia sobre o uso indiscriminado de assert e retract deve ser feita aqui. Os exemplos dados
ilustram algumas aplicaes obviamente teis desses predicados, entretanto o seu uso requer um cui-
dado especial. O uso excessivo e descuidado de tais recursos no recomendado como um bom estilo
de programao, uma vez que se est na realidade modificando o programa original em tempo de exe-
cuo. Assim, relaes vlidas em um determinado momento, podem no mais ser vlidas em um
momento subsequente, isto , em momentos diferentes, a mesma consulta pode ter respostas diferen-
tes. O uso abusivo de assert-retract pode obscurecer o significado do programa e dificultar a compre-
enso do que verdadeiro e o que no num dado instante. O comportamento resultante do programa
pode se tornar dificil de entender, de explicar e de confiar.
9.5 RECURSOS PARA O CONTROLE DE PROGRAMAS
A maioria dos recursos de controle de programas Prolog j foi apresentada anteriormente. Com vistas
a permitir uma viso conjunta de tais predicados, apresenta-se a seguir um resumo de todos eles:
cut: representado nos programas por "!", previne a execuo indesejada do mecanismo de
backtracking;
fail: um objetivo que sempre falha;
true: um objetivo que sempre bem sucedido;
not(P): um tipo de negao que se comporta exatamente como se houvesse sido definido por:
not(P) P, !, fail; true.
call(P): dispara um objetivo P. Ser bem-sucedido se e somente se P tambm o for;
repeat: um objetivo que sempre bem-sucedido. Sua principal propriedade ser no-
determinstico, isto , toda vez que alcanado por backtracking ele gera um caminho alternati-
vo para a execuo. Seu comportamento ocorre como se ele houvesse sido definido por:
repeat.
repeat :- repeat.
Uma forma tpica de uso desse ltimo predicado ilustrada pelo procedimento quadrado/0, que l
uma seqncia de nmeros e fornece o seu quadrado. A seqncia dada por concluda quando for
lido o tomo "fim", que sinaliza o encerramento da execuo:
quadrado :-
repeat, read(X),
(X=fim, !; Y is X*X, write(X), fail).
A construo acima tambm muito empregada em programas interativos, que possuem diversas al-
ternativas de execuo mutuamente exclusivas, como em um menu de opes:
executa :-
repeat, menu(X),
(X=fim, !; exec(X), fail).
Aqui um menu apresentado, uma ao selecionada, executada e o menu novamente apresentado,
repetindo-se esse ciclo at que a opo "fim" seja escolhida.
9.6 BAGOF, SETOF E FINDALL
Podemos gerar, atravs de backtracking, todos os objetos, um a um, que satisfazem algum objetivo.
Cada vez que uma nova soluo gerada, a anterior desaparece e no mais acessvel. Algumas ve-
90
zes, entretanto, deseja-se dispor de todos os objetos gerados, por exemplo, coletados em uma lista. .
Os predicados bagof/3 e setof/3 servem exatamente para tal propsito. O predicado findall/3 , em
algumas implementaes, oferecido como alternativa. O objetivo:
bagof(X, P, L)
ir produzir uma lista L de todos os objetos X que satisfazem ao objetivo P. Isto, naturalmente, s faz
sentido se X e P possuem alguma varivel em comum. Por exemplo, assumindo que temos em um
programa Prolog uma especificao que classifica letras em vogais
e consoante:
classe(a, vog).
classe(b, con).
classe(c, con).
classe(d, con).
classe(e, vog).
. . .
Ento podemos obter a lista de todas as consoantes nessa especificao atravs do objetivo:
?-bagof(Letra, classe(Letra, con), Consoantes).
Consoantes=[b, c, d, ..., z]
Se, neste ltimo objetivo, a classe das letras no estivesse especificada, obter-se-ia, por meio de
backtracking, duas listas, uma correspondendo s vogais e outra s consoantes:
?-bagof(Letra, classe(Letra, Classe), Letras).
Classe=vog Letras=[a, e, i, o, u];
Classe=con Letras=[b, c, d, f, ..., z].
Se no houver soluo para P no objetivo bagof(X, P, L), ento este simplesmente falha. Se algum
objeto X encontrado repetidamente, ento todas as suas ocorrncias iro aparecer em L, o que con-
duz possibilidade de existncia de elementos duplicados em L. O predicado setof/3 similar ao ba-
gof. O objetivo:
setof(X, P, L)
ir novamente produzir uma lista L dos objetos X que satisfazem a P, s que desta vez a lista L estar
ordenada e itens duplicados, se houver, sero eliminados. A ordem dos objetos estabelecida em fun-
o de sua ordem alfabtica ou de acordo com a relao "<" se os objetos na lista form nmeros. Se os
objetos forem estruturas, ento seus functores principais so comparados para fins de ordenao. Se
estes so iguais, ento a deciso fica por conta dos primeiros argumentos diferentes a contar da es-
querda.
No h restrio quanto ao tipo de objeto a ser coletado. Assim podemos, por exemplo construir uma
lista de pares da forma Classe/Letra de forma que as constantes apaream em primeiro lugar na lista
("con" antecede alfabeticamente "vog"):
?-setof(Classe/Letra, classe(Letra, Classe), Letras).
Letras=[con/b, con/c, ..., con/z, vog/a, ..., vog/u]
Um outro predicado dessa mesma famlia findall(X, P, L), que novamente produz a lista L de todos
os objetos X que satisfazem P. A diferena entre esse predicado e o bagof que todos os objetos X
so coletados sem considerar eventuais solues diferentes para as variveis em P que no so com-
partilhadas com X. Essa diferente ilustrada no seguinte exemplo:
?-findall(Letra, classe(Letra, Classe), Letras).
Letras=[a, b, c, ..., z]
Alm disso, se no h nenhum objeto X que satisfaa P, ento o predicado findall(X, P, L) resulta
bem-sucedido com L=[]. Caso o predicado findall/3 no se encontre entre os predicados pr-definidos
em uma determinada implementao Prolog, podemos program-lo facilmente da seguinte maneira:
findall(X, Objetivo, Lista) :-
call(Objetivo), assertz(soluo(X)), fail;
assertz(soluo(fim)), coleta(Lista).
91
coleta(Lista) :-
retract(soluo(X)), !,
(X==fim, !, Lista=[];
Lista=[X | Resto], coleta(Resto)).
No programa acima, todas as solues para o objetivo "Objetivo" so geradas por meio de
backtracking. Toda soluo gerada imediatamente includa na base de dados, de forma que no
perdida quando a prxima soluo encontrada. Depois de encontrar todas as solues, estas devem
ser coletadas em uma lista e retiradas da base de dados.
RESUMO
Uma implementao Prolog normalmente fornece um conjunto de predicados pr-definidos
para diversas operaes de uso frequente que nem sempre so de fcil codificao em Prolog
"puro";
O tipo de um termo Prolog pode ser testado por meio dos seguintes predicados pr-definidos:
var(X) X uma varivel no-instanciada,
nonvar(X) X no uma varivel no-instanciada,
atom(X) X um tomo,
integer(X) X um valor inteiro,
float(X) X um valor em ponto flutuante,
atomic(X) X um tomo ou um valor inteiro, e
string(X) X um string;
Termos Prolog podem ser construdos os decompostos atravs dos seguintes predicados pr-
definidos:
Termo =.. [Functor | Argumentos]
functor(Termo, Functor, Aridade)
arg(Ord, Termo, Argumento)
name(Atomo, Cdigos)
Os seguintes operadores pr-definidos so empregados na verificao de equivalncias e desi-
gualdades:
X = Y X e Y unificam,
X is E X o valor da expresso aritmtica E,
E1 =:= E2 E1 e E2 tem o mesmo valor,
E1 =\= E2 E1 e E2 tem valores diferentes,
T1 == T2 T1 e T2 so idnticos,
T1 \== T2 T1 e T2 no so idnticos;
Um programa Prolog pode ser visto como uma base de dados relacional, que pode ser atualiza-
da por meio dos seguintes predicados:
assert(Clusula)
asserta(Clusula)
assertz(Clusula)
retract(Clusula)
Um predicado pr-definido no-determinstico para o controle de programas o repeat/0, desti-
nado gerao de um nmero ilimitado de alternativas para o backtracking, que definido
como:
repeat.
repeat :- repeat.
Todos os objetos que satisfazem uma dada condio podem ser coletados em uma lista por
meio dos seguintes predicados:
bagof(Objeto, Condio, Lista)
setof(Objeto, Condio, Lista)
findall(Objeto, Condio, Lista)
EXERCCIOS
92
9.1 Escreva um procedimento denominado simplifica/2 para simplificar simbolicamente expresses
de soma envolvendo nmeros e tomos representandovariveis. O procedimento deve rearranjar a
expresso resultante de modo que os tomos precedam os nmeros. Alguns exemplos do seu uso
seriam:
?-simplifica(1+1+a, E).
E=a+2
?-simplifica(1+b+4+2+c+a, E).
E=a+b+c+7
?-simplifica(3+x+x, E).
E=2*x+3
9.2 Defina o predicado bsico(Termo), que verdadeiro se Termo no possui nenhuma varivel no-
instanciada.
9.3 Defina o relao subentende(Termo1, Termo2), que verdadeira se Termo1 "mais geral" que
Termo2. Por exemplo:
?-subentende(X, c).
sim
?-subentende(g(X), g(t(Y))).
sim
?-subentende(f(X, Y), f(a, a)).
sim
?-subentende(f(X, X), f(a, b)).
no
9.4 Defina a relao copia(Termo, Cpia), que produz em Cpia uma cpia de Termo com todas as
suas variveis renomeadas. Isso pode ser facilmente programado empregando os predicados as-
sert/1 e retract/1.
9.5 Use o predicado bagof/3 para definir a relao potncia(Conjunto, Subconjuntos), que computa o
conjunto de todos os subconjuntos de um dado conjunto, sendo todos os conjuntos representados
como listas. Por exemplo:
?-potncia([a, b, c], P).
P=[[], [a], [b], [c], [a, b], [a, c], [b, c], [a, b, c]]
93
10. LGICA E BASES DE DADOS
10.1 BASES DE DADOS RELACIONAIS
Uma "base de dados" pode ser entendida como uma coleo de dados interrelacionados, armazenada
de modo independente do programa que a utiliza, permitindo a recuperao, insero, remoo e mo-
dificao de forma controlada. A quantidade de dados tipicamente grande e o contedo muda ao
longo do tempo. Em Prolog, uma base de dados definida como um conjunto de fatos, no havendo,
entretanto, nada que impea a linguagem de trabalhar diretamente com bases de dados convencionais.
Alm disso a linguagem Prolog possui caractersticas que a tornam um excelente interface para lidar
com bases de dados relacionais.
Um dos marcos mais importantes no desenvolvimento da pesquisa acerca de bases de dados foi a in-
troduo do modelo relacional, por Codd em 1970. Em tal modelo, os dados so definidos por meio
de relaes sobre domnios e os fatos individuais so representados como tuplas de valores sobre tais
domnios. Uma relao com um conjunto de tuplas tambm denominada uma "tabela". O modelo
relacional conceitualmente muito "limpo" e elegante, apoiado por slida fundamentao matemti-
ca.
Diferentemente de outros modelos de bases de dados, o modelo relacional no possui o conceito de
"pointer", de modo que a associao entre diferentes tabelas feita atravs da identidade explcita de
valores de atributos. Este princpio concentra o esforo de implementao em obter maior velocidade
de acesso, ao passo que a vantagem natural a grande flexibilidade e fcil entendimento do processo
de modelagem de dados.
O modelo relacional tem produzido um grande esforo de pesquisa. O propsito de sua introduo
aqui tem sua origem no fato de que tabelas correspondem a uma forma muito natural de armazenar
fatos interrelacionados em Prolog.
10.1.1 EXEMPLO DE UMA BASE DE DADOS RELACIONAL
Considere as seguintes relaes:
pessoa/4, contendo nome, sexo, pai e me;
carro/4, contendo a placa, o fabricante, o proprietrio e a cor.
Tais relaes podem originar tabelas como as apresentadas abaixo:
Tabela 10.1(a): Relao pessoa/4
Nome Sexo Pai Me
Marcelo m Luiz Gilda
Luiz m Alfredo Lina
Gilda f Miguel Ana
Lcia f Luiz Gilda
Paulo m Miguel Ana
Lina f Francisco Jlia
94
Tabela 10.1(b): Relao carro/4
Placa Fabricante Proprietrio Cor
ABC-4590 Volkswagen Alfredo azul
XYZ-1211 Ford Lina branco
RTC-9004 Fiat Luiz vermelho
LLZ-7533 GM Gilda prata
Uma base de dados Prolog, formada a partir das tabelas 10.1(a) e (b), seria representada atravs dos
seguintes fatos:
pessoa(marcelo, m, luiz, gilda).
pessoa(luiz, m, alfredo, lina).
pessoa(gilda, f, miguel, ana).
pessoa(lcia, f, luiz, gilda).
pessoa(paulo, m, miguel, ana).
pessoa(lina, f, francisco, jlia).
carro(abc-4590, vw, alfredo, azul).
carro(xyz-1211, ford, lina, branco).
carro(rtc-9004, fiat, luiz, vermelho).
carro(llz-7533, gm, gilda, prata).
Um ou mais atributos em cada relao possui a propriedade especial de serem nicos na tabela. Tais
atributos so denominados "chaves" e identificam os objetos acerca dos quais armazenamos informa-
es. Usualmente se costuma sublinhar os atributos que so chaves, por exemplo:
pessoa:
nome sexo pai me
10.1.2 RELAES BINRIAS
As relaes mais simples que existem so as relaes binrias, que associam um nico atributo a cada
chave. A relao pessoa/4, que possui a chave "Nome", seria assim dividida em 3 relaes:
Nome-Sexo Nome-Pai Nome-Me
sexo(marcelo, m) pai(marcelo, luiz) me(marcelo, gilda)
etc... ... ...
o mesmo se aplica relao carro/4, cuja chave "Placa":
Placa-Fabricante Placa-Proprietrio Placa-Cor
Fabr(abc-4590, vw) pr(abc-4590, alfredo) cor(abc-4590, azul)
etc... ... ...
entretanto, por questes de convenincia e economia, toda a informao relacionada reunida em
uma nica relao.
Uma situao de exceo ocorre quando necessrio manipular informao incompleta no modelo
relacional. Em uma relao binria, a tupla correspondente desprezada, por exemplo, um carro sem
um proprietrio. Entretanto, no caso em que formada uma tupla com diversos atributos, um smbolo
especial "nil" empregado para representar tal informao. Por exemplo:
carro(ajk-6712, honda, nil, verde)
95
10.1.3 CHAVES COMPOSTAS
Em uma estratgia de implementao simples, assume-se que h uma nica chave em cada tupla,
normalmente ocupando a posio do primeiro argumento. Para chaves compostas assumiremos aqui
uma conveno ad-hoc, representando-as como uma lista de argumentos:
[ch1, ch2, ch3]
que possui o seu prprio nome, mantendo entretanto em separado os atributos individuais ch1, ch2 e
ch3.
10.2 RECUPERAO DE INFORMAES
Recuperar informaes significa combinar e apresentar o contedo da base de dados em uma forma
que satisfaa nossas necessidades. Em bases de dados convencionais isto executado por um progra-
ma que atua sobre a base de dados. Em Prolog isto feito atravs da definio das condies de solu-
o em lgica. Por exemplo:
Quem possui um fiat?
?-carro(_, fiat, Prop, _).
Prop = luiz
Quem fabrica os carros preferidos pelas mulheres?
?-pessoa(N, f, _, _), carro(_, Fabr, N, _).
N = lina Fabr = ford;
N = gilda Fabr = gm;
no
10.2.1 RECUPERAO EFICIENTE
Os sistemas Prolog permitem a representao de informao relacional e a sua recuperao facil-
mente formulada. Grandes bases de dados, entretanto, devem ser tratadas com cuidado, principal-
mente quando da combinao de tuplas distribudas em duas ou mais tabelas. Assim, sistemas Prolog
destinados a tais atividades normalmente devem possuir um "otimizador de consultas", que um pro-
grama escrito em Prolog que manipula consultas como se fossem dados de entrada expressos sob a
forma de termos, isto , tal programa desempenha o papel de um "meta-interpretador".
Uma estratgia possvel a empregar seria selecionar primeiro a condio que apresentasse o menor
nmero de solues possveis, supondo que todas as variveis estivessem instanciadas.
Suponha, por exemplo, que um crime tenha sido cometido e est sendo procurado um homem em um
ford azul. A base de dados da polcia possui duas tabelas: uma com 3000 carros e outra com 10000
pessoas suspeitas. Lembre-se que uma pessoa pode possuir mais de um carro. Vamos imaginar que
haja dez fords azuis e que metade das pessoas na base de dados sejam homens. H duas formas de
formular a questo:
?-carro(Placa, ford, X, azul), pessoa(X, m, _, _).
e
?-pessoa(X, m, _, _), carro(Placa, ford, X, azul).
Supondo que haja um acesso direto quando se dispe da chave da tabela, fcil verificar que, no pri-
meiro caso, sero realizadas 3000 tentativas de unificao na tabela de carros, dais quais apenas 10
sero bem sucedidas (s h 10 fords azuis), produzindo 10 acessos diretos tabela de pessoas para
verificar o sexo, num total de 3010 unificaes. No segundo caso, entretanto, sero realizadas primei-
ro 10000 tentativas de unificao na tabela de pessoas, das quais 5000 sero bem sucedidas. Para cada
uma dessas unificaes bem sucedidas, 3000 acessos devero ser feitos tabela de carros, uma vez
96
que no se dispe da chave, que "Placa". O nmero de tentativas de unificao realizadas aqui ser
portanto 5000 x 3000 + 10 = 15 000 010. Isso mostra porque as condies com o menor nmero de
solues possveis devem ser colocadas em primeiro lugar na formulao de consultas.
10.2.2 TABELAS VIRTUAIS
Uma das facilidades proporcionadas pelo Prolog no tratamento do modelo relacional a possibilidade
de definir novas tabelas sem ter de cri-las, empregando a implicao lgica. Tais tabelas so deno-
minadas "tabelas virtuais". Por exemplo, uma tabela corDoCarro/2 que contm como argumentos
somente a placa e a cor de um carro pode ser definida da seguinte maneira:
corDoCarro(X, Y) carro(X, _, _, Y).
O conceito de tabelas virtuais uma adaptao das "relaes extratoras" introduzidas no captulo an-
terior. Um subconjunto do Prolog convencional, sem os smbolos funcionais e o tratamento de listas,
denominado Datalog, foi proposto com essa finalidade. Na verdade o uso de Prolog para representar
bases de dados relacionais, introduz novos conceitos e regras, ampliando o nvel da informao.. Con-
sidere por exemplo a questo:
Quem tem uma av que possui um ford branco?
Em Prolog as regras para definir as relaes av/2, corDoCarro/2, etc. so facilmente construdas e
incorporadas base de dados, transcendendo o modelo relacional. A questo apropriada poderia ser
construda assim:
?-av(X, P), carro(_, ford, X, branco).
10.2.3 NOMES SIMBLICOS
Quando as tabelas Prolog so acessadas, o programa usa a posio do argumento na relao para aces-
sar a coluna correspondente. Isso se torna difcil, quando o nmero de argumentos muito grande.
Alm disso, constrange o programa a realizar concretamente as relaes. O que se necessita, portanto
uma representao mais abstrata que permita ao programa lidar com modificaes na modelagem
dos dados. Uma soluo empregar tabelas virtuais binrias, contendo o nome do atributo como ar-
gumento explcito. No caso de tabelas com muitos argumentos, esta tcnica pode se tornar uma neces-
sidade. Um predicado geral, atributo/4 pode ser definido para todos os nomes de atributos:
atributo(carro, P, placa, P) :- carro(P, _, _, _).
atributo(carro, P, fabricante, F) :- carro(P, F, _, _).
atributo(carro, P, proprietrio, X) :- carro(P, _, X, _).
atributo(carro, P, cor, C) :- carro(P, _, _, C).
10.3 ATUALIZAO DA BASE DE DADOS
O modelo relacional impe a restrio de que certos campos devem ser campos chaves, cujo valor
deve ser nico em uma tabela. Assim, "Nome " a chave na relao na relao pessoa/4, enquanto
que na relao carro/4 a chave "Placa". Em Prolog, um sistema para o gerenciamento de bases de
dados relacionais pode ser implementado de forma muito natural. As operaes bsicas so:
esquece(T) % Remove a tupla T
memoriza(T) % Insere a tupla T, se j no estiver l
atualiza(V, N) % Remove a velha e insere a nova tupla
Por exemplo:
?-esquece(carro(_, _, gilda, _)).
ir remover da base de dados todos os carros que pertencem a Gilda. Da mesma forma
memoriza(carro(flt-5455, honda, gilda, cor-de-rosa)).
ir introduzir o novo - e nico - carro de Gilda na base de dados.
97
Na construo dos predicados esquece/1 e memoriza/1, emprega-se a chave originalmente definida
como elemento de referncia, devendo-se preserv-la nica em qualquer circunstncia. Assim tais
predicados devem ser construdos na forma abaixo:
esquece(X) :-
esquece1(X), fail.
esquece(X).
esquece1(X) :-
retract(X).
esquece1(X).
memoriza(X) :-
esquece(X), assert(X).
memoriza(X) :-
assert(X).
O predicado esquece(X) ir excluir da base de dados todas as sentenas que unificam com X. Se for
desejada a excluso somente da primeira ocorrncia, deve ser usado o predicado esquece1(X). Am-
bos, esquece/1 e esquece1/1 so sempre bem sucedidos, garantindo o primeiro, com sua execuo, que
no h mais na base de dados nenhuma sentena que unifique com X e o segundo que a primeira sen-
tena encontrada unificando com X foi removida. Por outro lado o predicado memoriza(X) inicia com
uma chamada a esquece/1, preservando assim a unicidade da chave estipulada em X. Deve ser tam-
bm notado que esses predicados so extremamente poderosos e devem ser usados com absoluto cui-
dado para evitar "acidentes". Um cuidado interessante seria restringir a execuo de esquece/1, esque-
ce1/1 e memoriza/1 a argumentos que possussem uma instanciao explcita para a chave da tupla a
esquecer ou memorizar.
10.4 MODELAGEM DE DADOS
Uma base de dados no somente uma coleo de dados ou entidades, mas tambm as associaes ou
relacionamentos entre eles. Tais associaes constituem o denominado "modelo de dados". A tecno-
logia de bases de dados vem oferecendo mtodos e ferramentas para a soluo de problemas em am-
bientes complexos e de grande porte. O projeto de modelos lgicos de dados um importante objetivo
nas reas de representao e aquisio de conhecimento. O que se verifica que a pura lgica de pre-
dicados um formalismo extremamente poderoso, de expressividade ou capacidade de representao
virtualmente ilimitada, de modo que freqentemente temos que impor restries linguagem empre-
gada na modelagem, retornando porm lgica de predicados para explicar a semntica ou projetar
extenses no convencionais.
10.4.1 FORMAS NORMAIS
Como em toda modelagem, as nicas coisas importantes a serem modeladas so os invariantes fun-
damentais do domnio do problema. A mais importante propriedade dos invariantes que os objetos
pertencem a classes que podem ser armazenadas uniformemente como relaes.
Um outro princpio bsico aqui a evidncia de que um determinado dado em uma certa relao
funcionalmente dependente de outro. Um conjunto de dados B dito "funcionalmente dependente" de
um outro conjunto de dados A se para todo elemento a em A h um nico elemento b em B tal que b
est relacionado com a. As notaes mais empregadas so as seguintes:
A ---> B
A, B ---> C
significando respectivamente: "B funcionalmente dependente de A" e "C funcionalmente depen-
dente da combinao de A e B". Por exemplo:
trabalhador ---> empregador
Devido ao fato de que as chaves so nicas, segue automaticamente que todos os atributos de uma
98
entidade so funcionalmente dependentes de sua chave.
10.4.2 FORMAS NORMAIS RELACIONAIS
Outro importante princpio da boa modelagem de dados evitar redundncias. A mesma pea de in-
formao deve ser armazenada uma nica vez. Assim, para qualquer modificao em seus valores, a
base de dados necessitar ser atualizada em um nico ponto. Em bases de dados relacionais, tais prin-
cpios so definidos por meio de um processo denominado "normalizao". As diferentes formas
normais so denominadas: "primeira forma normal", "segunda forma normal", etc., e abreviadas res-
pectivamente por 1FN, 2FN, etc. Aqui introduzimos as trs primeiras delas.
PRIMEIRA FORMA NORMAL (1FN)
Evita repetir grupos, como no exemplo:
empregador empregado
1
, empregado
2
, ..., empregado
n
No usar a representao:
empregados(joo, [jos, jlia, jorge, josefina, jane]).
mas sim a representao
empr(jos, joo).
empr(jlia, joo).
empr(jorge, joo).
empr(josefina, joo).
empr(jane, joo).
onde os empregados (por exemplo, jos) no so funcionalmente dependentes do empregador (joo).
Ao contrrio, o empregador funcionalmente dependente dos empregados. Na prtica, o benefcio
acontece quando um novo empregado (por exemplo, jonas) contratado, porque tal fato pode ser in-
cludo na base de dados com:
?-memoriza(empr(jonas, joo)).
no necessitando o programador:
(1) Selecionar a lista de empregados de joo,
(2) Adicionar Jonas,
(3) Produzir uma nova lista,
(4) Apagar a tupla corrente, com a velha lista, e
(5) Produzir uma nova tupla, com a nova lista.
Um modelo na primeira forma normal deveria portanto ser:
empregador empregado.
SEGUNDA FORMA NORMAL (2FN)
Esta forma relevante para tuplas com chaves compostas:
empregado nomeEmpregado
empregado projeto nomeProjeto horas
Neste caso, cada empregado possui um nmero (a chave "empregado") e um nome (nomeEmpregado).
O empregado trabalha em um conjunto de projetos com nmeros (a chave "projeto") e nomes (nome-
Projeto), dedicando a cada um certo nmero de "horas".
99
A anomalia nesta representao que nomeProjeto no funcionalmente dependente da chave (em-
pregado, projeto) como um todo, mas apenas de uma parte dela (projeto). Assim a informao nome-
Projeto armazenada muitas vezes mais do que o necessrio. Se o nome do projeto muda, todas as
ocorrncias de nomeProjeto devem ser alteradas, uma vez para cada empregado que nele trabalha. Um
modelo na segunda forma normal seria:
empregado nomeEmpregado
empregado projeto horas
projeto nomeProjeto
Aqui nomeProjeto armazenado uma nica vez para cada projeto e modificado atravs de uma nica
atualizao.
TERCEIRA FORMA NORMAL (3FN)
Um bom exemplo da 3FN ocorre quando a informao sobre uma pessoa, seu empregador e o endere-
o de seu empregador so armazenados. Se a relao
empregado empregador endereoEmpregador
existe, ento a entidade endereoEmpregador no funcionalmente dependente da chave "emprega-
do" sozinha, mas na verdade de "empregador", que por sua vez dependente de "empregado". Como
nos casos anteriores, problemas de redundncia e de mltiplas atualizaes surgem, de modo que a
normalizao recomenda que a relao acima seja dividida em duas relaes independentes:
empregado empregador
empregador endereoEmpregador
Os princpios da normalizao podem ser aplicados manualmente para modelos pequenos, entretanto,
para grandes modelos a normalizao deve preferencialmente ser apoiada por ferramentas de enge-
nharia de software.
10.5 ALM DO MODELO RELACIONAL
O modelo relacional puro nem sempre poderoso o bastante para modelagens avanadas, devido
falta de expressividade semntica . Por exemplo, o modelo relacional no requer que, para cada em-
pregado, o atributo empregador corresponda a uma tupla existente na base de dados. Em modelos
reais h dois tipos de regras que relacionam as tabelas uma outra:
regras genricas, que definem novas tabelas virtuais que no so explicitamente armazenadas, e
regras restritoras, que estabelecem restries sobre o que permitido na base de dados.
Um exemplo de regras restritoras dada pelas dependncias funcionais, que especificam que atribu-
tos-chave so e devem ser nicos. Um outro exemplo seria uma regra como:
"Todos os elefantes so cor-de-cinza."
que deduz a cor de um elefante na base de dados, produzindo ainda uma restrio que garante que, nas
atualizaes subsequentes, nenhum elefante de outra cor ser armazenado na base de dados. Tais ba-
ses de dados so denominadas "dedutivas".
10.6 REDES SEMNTICAS
Questes de semntica so mais importantes para o projeto de uma base de conhecimento do que do
que mtodos para a codificao de dados. Quando os projetistas de base de dados adicionam mais
informao semntica s bases de dados, os modelos resultantes comeam a assemelhar-se aos siste-
mas de representao de conhecimento desenvolvidos pelos pesquisadores de inteligncia artificial.
Um desses esquemas de representao de conhecimento conhecido como "rede semntica". Uma
100
rede semntica um formalismo para representar fatos e relacionamentos entre fatos por meio de
relaes binrias. Por exemplo, na Figura 10.1, Jos, Joo e 555-2455 representam objetos. "telefone"
representa uma relao entre os objetos Jos e 555-2455, enquanto que "empregador" representa uma
relao entre Jos e Joo.
Jos
555-2455
Joo
telefone
empregador
Figura 10.1: Uma rede semntica simples
Os relacionamentos individuais so conectados em uma rede, onde os objetos, por exemplo, "Jos",
so representados uma nica vez. Para relaes binrias, as redes semnticas so um excelente forma-
lismo com uma notao grfica simples. Quando se tenta, entretanto, representar relaes n-rias em
redes semnticas -se forado a empregar construes artificiais, perdendo o formalismo das redes
semnticas grande parte dos seus atrativos.
Acredita-se que grande parte do raciocnio humano seja baseado em associaes lineares, de modo
que o modelo das redes semnticas tambm um interessante modelo do pensamento humano. Em
Prolog as relaes binrias so implementadas individualmente, repetindo os nomes dos objetos como
em:
telefone(jos, 555-2455).
empregador(jos, joo).
Armazenar uma rede semntica como uma rede com ponteiros um mtodo de implementao que
oferece rpido acesso no processo de associao. Em Prolog, na falta do conceito de ponteiro, as redes
so armazenadas como relaes binrias. Isto um pouco mais lento, mas muito flexvel, tanto para
recuperar informaes quanto para sua atualizao.
10.6.1 O CONCEITO DE CLASSE
To logo um objeto classificado, grande quantidade de conhecimento se torna disponvel a seu res-
peito. Uma "classe" a descrio de atributos e propriedades que so comuns a determinados indiv-
duos, denominados os "membros" da classe. Jos, por exemplo, um objeto pertencente classe dos
empregados. Um "atributo" alguma coisa que pode assumir um valor. Telefone, por exemplo, um
atributo dos membros da classe dos empregados. Uma "propriedade" um atributo juntamente com
um valor. Por exemplo, uma rosa tem a propriedade cor = vermelha. Jos tem a propriedade telefone =
555-2455.
Uma classe pode ser vazia, por exemplo, a classe dos unicrnios, e duas classes com os mesmos ele-
mentos podem ser bastante diferentes, por exemplo, a classe dos diretores de pesquisa e a classe dos
possuidores de aqurios. So exemplos de classes:
animal
mamfero
baleia
elefante
101
tubaro
So exemplos de atributos:
cor
alimento
habitat
tamanho
temperamento
Uma classe pode ser subclasse de outra classe. Se S uma subclasse de C e x membro de S, ento x
tambm membro de C. Por exemplo, "mamfero" uma subclasse de "animal" e "elefante" uma
subclasse de "mamfero". Se Clyde um elefante (isto , um membro da classe elefante), ento Clyde
ao mesmo tempo membro da classe mamfero e portanto tambm membro da classe animal.
Se a classe possui um atributo, este compartilhado por todas as suas subclasses. Note que uma classe
pode ter um atributo, mesmo se no possui membros no momento. Valores de atributos inexistentes,
tais como o telefone de um elefante, so rejeitados como no significativos, no devendo ser empre-
gado o tomo "nil".
De modo similar, se uma entidade possui um atributo que funcionalmente dependente dela, por
exemplo, "toda pessoa tem um nome", e o valor do atributo estiver faltando, o tomo apropriado para
representar isso "desconhecido" e no "nil" ou algo parecido. Se, por outro lado, um atributo no
funcionalmente dependente, tal como os filhos de uma pessoa, ento a sua ausncia deve ser pelo
tomo "nil" ou "nenhum" e no por "desconhecido".
Por exemplo: todos os animais tem uma cor, que varia. Portanto, todos os mamferos tem uma cor. Os
elefantes, portanto, tem uma cor, de modo que Clyde, que um elefante, tem tambm uma cor. Se a
classe tem uma propriedade, esta automaticamente herdada por todos os seus membros. Por exem-
plo:
"Todos os elefantes tem uma cor = cinza"
implica em:
"Se Clyde um elefante, ento Clyde tem uma cor = cinza"
O armazenamento de informao sobre classes em conjunto com informao sobre objetos, requer
alguns relacionamentos de uso geral, como os apresentados na figura 10.2
A
E
A
A
A
B
B
B
B
V
um tipo de
_um

tem
atributo
A subclasse de B
A entidade E um B
B adjetivo de A
A tem um atributo B
A tem um valor de atributo V
Figura 10.2 Relacionamentos em Redes Semnticas
102
animal
oxignio
mamfero Bonnie
amendoim elefante baleia tubaro
Clyde
circo
cinza
oceano
umTipoDe
umTipoDe
umTipoDe
Um
inalante
umTipoDe
alimento
Um
habitat
cor
cor
habitat
cor
Figura 10.3 Uma rede semntica
Seja ento a rede semntica mostrada na Figura 10.3. A informao ali representada pode ser adequa-
damente descrita atravs de um conjunto de clusulas Prolog. A declarao de operadores infixos
contribui para tornar o programa mais legvel. Define-se assim a sintaxe dos relacionamentos descri-
tos na Figura 10.2 por meio da assertiva:
:- op(900, xfx, [UmTipoDe, Um, , tem, atributo]).
O seguinte programa Prolog descreve a rede semntica acima:
:- op(900, xfx, [UmTipoDe, Um, , tem, temUm]).
animal temUm inalante.
animal temUm alimento.
animal temUm habitat.
animal temUm cor.
mamfero UmTipoDe animal.
mamfero tem inalante=oxignio.
elefante UmTipoDe mamfero.
elefante tem alimento=amendoim.
elefante tem habitat=circo.
elefante tem cor=cinza.
baleia UmTipoDe mamfero.
baleia tem habitat=oceano.
baleia tem cor=cinza.
tubaro UmTipoDe animal.
tubaro tem habitat=oceano
tubaro tem cor=cinza
bonnie Um tubaro.
clyde Um elefante.
A estrutura de classes em redes semnticas definida pelos seguintes axiomas:
X Um Z2 :-
Z1 UmTipoDe Z2, X Um Z1.
X tem Atributo=Valor :-
X Um C, C tem Atributo=Valor.
O primeiro destes axiomas o fecho transitivo de Um/2 e o segundo o fecho transitivo de tem/2.
Com o emprego deles possvel consultar a base de conhecimento em busca de questes de carter
geral tais como:
"Que propriedades possui Clyde?"
?-clyde tem Atr=Val.
Atr=alimento Val=amendoim;
Atr=habitat Val=circo;
Atr=cor Val=cinza;
Atr=inalante Val=oxignio;
no
103
RESUMO
Em bases de dados relacionais os dados so definidos por meio de relaes sobre domnios, e
os fatos individuais so representados como tuplas de valores extrados de tais domnios, cada
um deles representando um "atributo";
Pelo menos um dentre os atributos possui a caracterstica especial de ser "nico" em toda a ta-
bela de tuplas. Tal atributo denominado uma "chave" e identifica os objetos acerca dos quais
armazenada informao;
Duas facilidades importantes oferecidas pelo modelo relacional so as tabelas virtuais, que de-
finem relacionamentos implcitos, e o uso de nomes simblicos;
A atualizao de base de dados deve ser projetada de modo a preservar a unicidade dos atribu-
tos-chave. Os predicados esquece/1, esquece1/1 e memoriza/1 foram desenvolvidos com essa
idia em mente;
Na modelagem de dados importante a adoo de formas normalizadas para garantir certos
princpios organizacionais, evitando redundncias e a necessidade de realizar mltiplas atuali-
zaes;
Nem sempre o modelo relacional ir apresentar a expressividade necessria para a modelagem
avanada. Um modelo mais expressivo, empregado em inteligncia artificial o das redes se-
mnticas;
A modelagem atravs de redes semnticas introduz os conceitos de classe e herana de atribu-
tos, os quais so de fcil construo em Prolog;
Alguns dos relacionamentos empregados em redes semnticas so: UmTipoDe, Um, , tem e
temUm. Todos eles so binrios, e podem ser representados em Prolog por meio de operadores
infixos.
EXERCCIOS
10.1 Defina duas relaes:
empr(Nome, Depto, Salrio)
depto(Departamento, Gerente)
Escreva uma consulta ao sistema Prolog respondendo "Que empregados possuem salrio superior
ao de seu gerente?"
10.2 Defina as seguintes relaes:
pas(X) % X um pas
mar(X) % X um mar
populao(X,Y) % X tem a populao Y
fronteira(X, Y) % X faz fronteira com Y
Escreva uma consulta ao sistema Prolog para responder a questo: "Que pas, banhado pelo me-
diterrneo, faz fronteira com um pas que faz fronteira com um pas cuja populao excede a po-
pulao da ndia?"
10.3 Modifique os predicados para a manipulao de bases de dados relacionais apresentados no pre-
sente captulo de forma que mltiplas chaves sejam armazenadas sem redundncia. (Dica: Use
tabelas virtuais).
10.4 Amplie a base de conhecimento sobre animais. Como representar um avestruz como membro da
classe dos pssaros se se definiu "voar" como uma propriedade dessa classe? Em outras palavras,
como introduzir o conceito de exceo nas propriedades herdadas por um objeto a partir de sua
classe?
104
10.5 Modele uma base de conhecimento, empregando redes semnticas para descrever automveis,
introduzindo os relacionamentos ParteDe(X, Y), que verdadeiro se X parte de Y (por exem-
plo: ParteDe(motor, carro)) e subconjDe(X, Y), que verdadeiro se X subconjunto de Y.
105
11. PROGRAMAO SIMBLICA
11.1 DIFERENCIAO SIMBLICA
Um exemplo conhecido de manipulao de frmulas sem o emprego de computao numrica a
diferenciao de funes matemticas. As regras so simples e diretamente implementadas em Prolog
de uma forma muito elegante, empregando to somente o mecanismo de unificao. No presente
exemplo, todas as diferenciaes iro se referir a uma varivel matemtica fixa, x, que ser tratada
como uma constante pelo sistema Prolog. As regras de diferenciao so definidas pelo predicado
deriv(U, V), que verdadeiro quando V = dU / dx:
deriv(x, 1).
deriv(N, 0) :-
number(N). % number/1: embutido
deriv(U+V, U1+V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U-V, U1-V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U*V, U1*V+U*V1) :-
deriv(U, U1),
deriv(V, V1).
deriv(U/V, (V*U1-V1*U)/(V*V)) :-
deriv(U, U1),
deriv(V, V1).
deriv(U^N, N*U^(N1*U1)) :-
number(N),
N1 is N-1,
deriv(U, U1).
deriv(exp(U), exp(U)*U1) :-
deriv(U, U1).
...
Por exemplo:
?-deriv(x*x, Y).
Y=1*X+X*1
Entretanto, certamente seria mais apreciada uma sada melhor, tal como 2*X ou simplesmente 2X. A
razo da apresentao inadequada do resultado que o Prolog no possui simplificao algbrica
inerente, entretanto esta pode ser facilmente implementada, como ser visto mais adiante neste mesmo
captulo.
11.2 MANIPULAO DE FRMULAS
Em uma linguagem de programao simblica, como Prolog, os programadores precisam considerar
as frmulas e no apenas os seus valores. Em geral as frmulas no envolvem apenas aritmtica, mas
podem ser combinadas arbitrariamente atravs dos mais variados operadores e operandos, de acordo
com o princpio recursivo da decomposio: "o valor de uma expresso o resultado da aplicao de
um operador ao resultado dos restantes".
Em linguagens como Pascal e Lisp este princpio recursivo parte da semntica da linguagem. Em
Prolog isto deve ser feito explicitamente, mas pode ser feito sem dificuldades por um predicado recur-
sivamente definido. Este esquema geral e uma rplica do princpio recursivo da decomposio:
"Para resolver uma expresso, primeiro (i) resolva seus operandos, e depois (ii) aplique o
operador sobre os resultados obtidos".
11.3 OS OPERADORES REVISITADOS
106
Para lidar com uma expresso, necessrio ser capaz de manipular os seus subcomponentes. Na Ta-
bela 11.1 relaciona-se um conjunto de operadores embutidos disponveis na maioria das implementa-
es Prolog. H-se que lembrar entretanto que internamente tais operadores so representados sob a
forma de termos funcionais, onde os operadores so functores. Por exemplo:
X+Y armazenado como '+'(X, Y)
O operador embutido =../2 (univ) capaz de atuar sobre uma expresso vista como uma lista de com-
ponentes:
X+Y =.. ['+', X, Y]
-X =.. ['-', X]
Por exemplo:
?- 3+2*7 =.. [X, Y, Z].
X='+' Y=3 Z=2*7
?-X =.. ['-', 3+5, 5*9].
X=3+5-5*9
Tambm so importantes neste contexto os predicados embutidos functor/3 e arg/3 (ver seo 9.2) que
atuam normalmente sobre operadores, empregando a notao funcional.
Tabela 11.1 Operaes Comuns em Prolog
(a) Operaes Binrias
X+Y Adio
X-Y Subtrao
X*Y Multiplicao
X/Y Diviso
X=Y Igual
X<>Y No igual
X>=Y Maior ou Igual
X=<Y Menor ou Igual
X<Y Menor que
X>Y Maior que
X and Y Conjuno
X or Y Disjuno
X impl Y Implicao
(b) Operaes Unrias
-X Negao Aritmtica
not X Negao Lgica
11.4 AVALIAO DE FRMULAS
O efeito do operador "is" conhecido:
?-X is 3*7*37.
X=777
?-X is 7*11*13.
X=1001
A avaliao das frmulas numricas escondida do usurio, apesar de poder ser definida em Prolog.
Sua implementao em Prolog til por duas razes: Primeiro para ensinar os princpios da avaliao
de frmulas em Prolog. Depois, pode vir a ser necessrio incluir regras de operao que no se com-
portam estritamente com a semntica do operador "is". Vamos agora implementar o operador "$" com
a finalidade de estender os efeitos de "is", de modo que a expresso seja esperada do lado esquerdo e
o valor direita, assim:
10 + 10 $ 20
107
que pode ser lido: "o valor de 10+10 20". O operador "$" estende o "is" tambm na avaliao de
variveis globais, armazenadas como valor(A, B). Por exemplo:
valor(a, 3).
valor(b, 7).
?-a*b*37 $ X.
X=777
A avaliao estendida, $, definida da seguinte maneira:
:- op(900, xfx, '$').
(X $ X) :-
number(X), !.
(X $ Y) :-
valor(X, Y), !.
V $ U :-
V =.. [Op, X, Y], !, X $ X1, Y $ Y1,
W=.. [Op, X1, Y1], U is W.
V $ U :-
V =.. [Op, X], !, X $ X1, W=..[Op, X1], U is W.
O operador $ pode ser usado para implementar a atribuio ordinria de variveis globais como no
programa abaixo, onde o predicado esquece/1 o mesmo introduzido no captulo anterior e repetido
aqui como recordao:
:- op(901, xfx, ':=').
(V:=E) :-
E $ T, esquece(valor(V,X)), assert(valor(V, T)).
esquece(X) :-
esquece1(X), fail.
esquece(X).
esquece1(X) :-
retract(X).
esquece1(X).
A partir da definio acima podemos escrever:
?-a:=4, b:=13, c:=b*a, valor(c, X).
X=52
11.5 SIMPLIFICAO ALGBRICA
Outras aplicaes importantes da programao simblica so a manipulao de frmulas, prova de
teoremas no domnio da matemtica e anlise de programas. A prova de teoremas tambm parte
integrante da disciplina de verificao de programas, progrando a correo de programas. Um teorema
pode ser provado se pode ser reduzido constante "true". Descreve-se inicialmente aqui a simplifica-
o algbrica.
H diversas regras para as vrias frmulas, por exemplo, as leis comutativa, associativa e distribuitiva.
Na rea da simplificao algbrica, as regras que reduzem a complexidade das frmulas so especial-
mente interessantes. Algumas dessas regras so fornecidas abaixo atravs do predicado reduz/2.
A partir dos axiomas bsicos de reduo apresentados na figura acima, um pequeno programa simpli-
ficador pode ser construdo baseado no seguinte princpio recursivo:
Simplifique os operandos primeiro, depois a operao, e
Repita at que nenhum dos operandos seja modificado.
reduz(X+0, X). reduz(X=X, true).
reduz(0+X, X). reduz(X or true, true).
redux(X-X, 0). reduz(true or X, true).
reduz(X-0, X). reduz(X and false, false).
reduz(0-X, -X). reduz(false and X, false).
reduz(X*0, 0). reduz(X and true, X).
108
reduz(0*X, 0). reduz(true and X, X).
reduz(X*1, X). reduz(X or false, X).
reduz(1*X, X). reduz(false or X, X).
reduz(0/X, 0). reduz(X impl true, true).
reduz(true impl X, X).
reduz(false impl X, true).
reduz(X impl X, true).
reduz(X and X, X).
reduz(X or X, X).
reduz(U, V) :-
U =..[Op, X, Y], number(X), number(Y), !, V is U.
Figura 11.1 O predicado reduz/2
O algoritmo est correto, porm no completo. Tambm no possui eficincia tima porque ir ten-
tar ressimplificar uma expresso que um algoritmo mais refinado reconheceria como j simplificada.
Tal refinamento ser deixado ao leitor a ttulo de exerccio.
simplifica(U, V) :-
simp(U, V, Teste). % Teste verdadeiro se V<>U.
simp(F, H, true) :-
reduz(F, G), !, simplifica(G, H).
simp(F, Z, true) :-
F=..[Op, X, Y],
simp(X, X1, mudaX),
simp(Y, Y1, mudaY),
membro(true, [mudaX, mudaY]), !,
G=..[Op, X1, Y1],
simplifica(G, Z).
simp(F, F, false).
O efeito do programa acima pode ser visualizado por meio dos seguintes exemplos:
?-simplifica(1*x-x*1, S).
S=0
?-simplifica(1*x+x*1, S).
S=x+x
A diferenciao e a simplificao algbrica podem agora ser integradas em um s predicado:
deriva(U, V) :-
deriv(U, U1), simplifica(U1, V).
?-deriva(x*x, S).
S=x+x
11.5.1 SUBEXPRESSES COMUNS
A simplificao possvel quando operaes adjacentes podem ser encontradas por meio do reconhe-
cimento de padres fixos. Por exemplo:
(a+b*j-f) - (a+b*j-f)
reconhecido pela unificao com o padro X-X. Entretanto, uma classe de problemas resta ainda por
ser solucionada, que quando h subexpresses que poderiam ser movidas de acordo com as regras
comutativas e associativas, e ento reduzidas quando um padro unificvel for reconhecido. A expres-
so
(a+b+c)-b
poderia ser transformada em
((a+c)+b)-b
que segue o padro:
(X+Y)-Y
sendo redutvel a
X=a+c
109
Na verdade a formao de subexpresses comuns um dos importantes princpios heursticos que de
que se valem as pessoas na realizao de simplificaes algbricas. A tarefa bsica, no caso, desco-
brir subexpresses comuns.
Uma subexpresso ocorrendo em uma expresso facilmente formulada como:
ocorre(X, X).
ocorre(S, Z) :-
Z=..[Op, X, Y], (ocorre(S, X); ocorre(S, Y)).
de modo que o problema de descobrir se uma determinada expresso emprega a mesma subexpresso
diversas vezes solucionado por:
comum(Z, U) :-
Z=..[Op, X, Y], ocorre(U, X), ocorre(U, Y).
Por exemplo:
?-comum((w+1+2*(w+1)), Z), fail.
w+1
w
1
no
11.6 INTEGRAO
Tem sido dito que a diferenciao uma tcnica, ao passo que a integrao uma arte. A tarefa de
integrao simblica objeto da engenharia de conhecimento, onde as especializaes humanas so
transferidas para sistemas computacionais. Uma primeira tentativa de obter integrao poderia ser por
meio da explorao da reversibilidade dos predicados Prolog :
integr(Y, Z) :-
deriv(Z, Y).
?-integr(1*x+x*1, Int).
Int=x*x
Infelizmente a capacidade Prolog de inverter predicados limitado. Se for solicitado:
?-integr(0, Int).
em um determinado momento ser ativado o objetivo number(Int). Entretanto, tal predicado pr-
definido no inversvel. Se o fosse, deveria gerar nmeros instanciados (0, 1, 2, ...) , que so todos
integraes corretas de 0. Mas ao invs disso produz a penas a resposta "no".
Um outro problema diz respeito a reverso da simplificao. Se for tentado
?-integr(x+x, Int).
com vistas a obter x*x, nenhuma resposta obtida, porque x+x somente atingido aps uma simplifi-
cao. Se simplifica/2 estiver sendo executado de modo reverso, ir cair num lao recursivo infinito.
Entretanto, possvel modificar o predicado simplifica/2 para controlar a profundidade mxima da
recurso. Essa aplicao pode resultar em um sistema de integrao simblica bastante lento, mas
teoricamente completo, baseado no princpio da gerao e teste exaustivos. A construo de tal siste-
ma deixada como um exerccio ao leitor.
RESUMO
A capacidade de programao simblica uma das principais caractersticas da linguagem
Prolog. A diferenciao facilmente implementada atravs de suas regras;
O princpio recursivo de decomposio que parte da semntica de linguagens tais como Pas-
cal e Lisp, deve ser explicitado em Prolog, o que pode feito com grande facilidade;
110
Os predicados embutidos =../2, functor/3 e arg/3 so de grande valia na programao simblica
para a separao dos subcomponentes das expresses;
O operador "$" estende a semntica do operador "is" permitindo a avaliao de variveis glo-
bais e a implementao do mecanismo de atribuio de valores;
A simplificao algbrica implementada simbolicamente por meio do predicado reduz/2, que
associa os fatos e regras relevantes para a simplificao desejada;
A identificao de subexpresses comuns para fins de simplificao necessita de heursticas es-
peciais para ser eficiente. O predicado comum/2, baseado em ocorre/2, representa uma imple-
mentao simples com esse objetivo;
A integrao pode ser implementada em parte como o inverso da diferenciao, entretanto as
limitaes de reversibilidade do Prolog iro exigir o uso de estratgias e heursticas especiais
para a execuo desta tarefa.
EXERCCIOS
11.1 Escreva um programa de simplificao que nunca re-simplifique uma expresso j simplificada.
11.2 Estenda o predicado deriva/2, incluindo simplificao algbrica para lidar com as funes:
ln, exp, sin, cos, arctan e U^V
onde U e V so expresses genricas.
11.3 Estenda o exemplo das subexpresses comuns para levar em conta a equivalncia comutativa.
11.4 Escreva um programa Prolog para mover subexpresses comuns para prximas umas das outras e
ento executar redues com base no reconhecimento de padres, tal como antes. Por exemplo:
(a+b+c+d - (a+c))
Aqui, c uma subexpresso comum que removida dos dois operandos principais:
(a+b+c+d) ==> ((a+b+d) + c)
-(a+c) ==> -(a+c)
----------------------------
(a+b+d) - a
e ento reduzida de acordo com o padro:
(X+C)-(Y+C) ==> X - Y
que aplicado recursivamente produz o resultado (b + d)
11.5 Modifique o predicado deriva/2 para obter a integrao por inverso da derivao e a simplifica-
o de acordo com o esquema:
integralN(U, V, N) :-
nvel(N), simplificaN(Frmula, U, N), deriv(U, Frmula).
nvel(0).
nvel(N1) :- nvel(N), N1 is N+1.
onde simplificaN/3 simplifica uma frmula em exatamente N passos recursivos (N = 0, 1, ...).
111
12. METODOLOGIA DA PROGRAMAO EM LGICA
A engenharia de software estabeleceu, ao longo do tempo, diversos critrios para a caracterizao de
programas de boa qualidade, assim como tcnicas e prticas que, se empregadas, conduzem natural-
mente construo de bons programas. Ainda que tais tcnicas tenham sido desenvolvidas geralmente
do ponto de vista da programao procedimental convencional, importante lembrar que programas
em Prolog so tambm software e como tal devem estar sujeitos mesma disciplina e mtodo preco-
nizados para o desenvolvimento de programas convencionais.
O estilo declarativo inerente linguagem Prolog permite solucionar automaticamente diversos pro-
blemas relacionados com a recuperao de informaes e representao de estruturas complexas de
dados, entretanto, uma boa parte dos problemas com que se deparam os programadores so algortmi-
cos por natureza, devendo portanto ser interpretados e solucionados de forma algortmica.
No presente captulo so revisados alguns princpios gerais da engenharia de software, abordando os
elementos necessrios ao desenvolvimento de um bom estilo de programao em Prolog. Critrios de
correo e eficincia so tambm introduzidos, visando oferecer ao leitor alguma instrumentao
metodolgica para a construo de programas de boa qualidade.
12.1 PRINCPIOS GERAIS DA BOA PROGRAMAO
Uma questo fundamental a esse respeito : "O que um bom programa?". A resposta a esta questo
no tarefa trivial, uma vez que h diversos critrios para julgar quo bom um programa . Critrios
geralmente aceitos incluem, entre outros, os seguintes:
CORREO: Acima de tudo, um programa deve ser "correto", isto , deve fazer exatamente o
que se espera dele. Um erro comum, cometido por alguns programadores negligenciar esse
critrio bvio em favor de outros, como por exemplo a eficincia;
EFICINCIA: Um bom programa no deve consumir sem necessidade grandes quantidades de
recursos, tais como memria e tempo de execuo;
TRANSPARNCIA E LEGIBILIDADE: Um bom programa deve ser fcil de ler e entender.
No deve ser mais complicado do que o necessrio. Truques de programao que obscurecem o
significado do programa devem ser evitados;
MODIFICABILIDADE: Um bom programa deve ser fcil de ser modificado ou estendido. A
transparncia e a adoo de uma organizao modular auxiliam a atingir tal objetivo;
ROBUSTEZ: Um bom programa deve ser "robusto". Isso significa que ele no deve ser aborta-
do facilmente quando o usurio entrar com dados incorretos ou inesperados. O programa deve,
no caso de tais erros, manter-se em execuo e comportar-se "racionalmente" (por exemplo:
relatando o erro ao usurio e solicitando nova entrada de dados).
DOCUMENTAO: Um bom programa deve ser adequadamente documentado. A documenta-
o mnima aceitvel para um programa a sua listagem enriquecida com comentrios sufici-
entes para o seu entendimento.
A importncia de cada critrio vai depender do problema, das circunstncias em que o programa
desenvolvido e do ambiente em que ser utilizado. No h dvida, entretanto, de que a correo deve
ser o critrio de mais alta prioridade. Aos critrios de transparncia, modificabilidade, robustez e do-
cumentao normalmente atribuda uma prioridade no mnimo igual ao requisito de eficincia.
112
H algumas regras gerais para atingir na prtica os critrios apresentados acima. Uma delas, muito
importante, primeiro "pensar" sobre o problema a ser resolvido e somente iniciar a codificao na
linguagem de programao escolhida depois de se ter formulado uma idia clara sobre o que deve ser
feito. Uma vez que um bom entendimento do problema foi desenvolvido e definida a sua soluo, a
codificao do programa torna-se fcil e rpida, havendo uma boa chance de se obter sem demora um
programa correto.
A formulao inicial obtida para a soluo do problema dever ento ser convertida para a linguagem
de programao escolha. Tal processo, entretanto, pode no ser uma tarefa fcil. Uma abordagem
consagrada a de utilizar o "princpio dos refinamentos sucessivos", que considera a soluo inicial
uma formulao em "alto nvel" e o programa finalmente obtido como uma soluo em "baixo nvel".
De acordo com o princpio dos refinamentos sucessivos, o programa final obtido por meio de uma
sequncia de transformaes ou refinamentos da soluo inicial. Inicia-se com a formulao em alto
nvel da soluo do problema e ento passa-se a transform-la de maneira que cada nova formulao
obtida equivalente anterior, porm expressa de forma mais detalhada. Em cada passo de refina-
mento os conceitos usados na formulao anterior so elaborados em maior detalhe e a sua represen-
tao vai se aproximando da linguagem de programao. Deve-se ter em mente que os refinamentos
se aplicam tanto s definies de procedimentos quanto s estruturas de dados. Nos estgios iniciais
normalmente se trabalha com unidades de informao mais abstratas, cuja estrutura refinada na me-
dida em que avanamos com o processo. A estratgia dos refinamentos sucessivos possui as seguintes
vantagens:
Permite a formulao de uma soluo inicial nos termos mais relevantes ao problema,
Essa soluo inicial , por conseguinte, mais simples e sucinta, sendo a sua correo facilmente
verificvel, e
Cada passo de refinamento deve ser suficientemente pequeno para ser manejado intelectual-
mente. Assim a transformao da soluo em uma representao mais detalhada preserva com
mais facilidade a sua correo.
No caso da linguagem Prolog, pode-se pensar em tal processo como sendo o de refinamento de refi-
namento de relaes. Se, entretanto, a natureza do problema sugerir uma abordagem em termos algo-
rtmicos, tambm possvel pensar em refinamento de algoritmos, adotando ento a viso procedi-
mental do Prolog.
Para refinar apropriadamente uma soluo em algum nvel de detalhamento e introduzir conceitos
adequados ao prximo, necessrio "ter idias". Portanto a programao uma atividade criativa,
especialmente para programadores iniciantes. medida em que a experincia em programao au-
menta, esta se torna menos uma arte e mais uma tcnica. Assim, a questo principal : "Como ter idi-
as?" A maioria das idias surge da experincia com problemas similares, cuja soluo conhecida. Se
no se conhece uma soluo direta, pode-se lanar mo de outros programas parecidos. Uma fonte de
idias nossa vida no dia-a-dia.. Por exemplo, se o problema a resolver classificar uma lista de
itens, pode-se obter uma idia considerando a questo: "Como proceder para classificar as provas de
uma turma de alunos pela ordem alfabtica do nome dos estudantes?".
12.2 COMO PENSAR EM PROLOG
Uma caracterstica importante da linguagem Prolog permitir que seus programas sejam pensados
tanto declarativa quanto procedimentalmente. Essas duas abordagens foram discutidas com algum
detalhe no captulo 3. A que ir se tornar mais eficiente e prtica depende, naturalmente, do problema
a resolver. A experincia tem mostrado que solues declarativas so usualmente mais fceis de des-
envolver e possuem a clareza e limpidez da pura lgica. Por outro lado, podem tambm facilmente
originar programas ineficientes. Durante o processo de desenvolvimento de uma soluo, deve-se
113
buscar as idias adequadas para decompor um problema em subproblemas de soluo mais fcil. Uma
questo importante aqui : "Como encontrar os subproblemas apropriados?". Os princpios funda-
mentais para responder tal questo sero discutidos agora.
12.2.1 USO DE RECURSO
Na soluo de problemas envolvendo o processamento sequencial por meio de recurso, uma boa
heurstica aplicar pensamento indutivo e resolver os seguintes dois casos separadamente:
(1) Os casos triviais, ou bsicos, em que o argumento uma lista vazia ou unitria, e
(2) Os casos gerais, em que o argumento uma lista [Cabea|Corpo] e o problema assumido re-
solvido para "Corpo".
Em Prolog, essa tcnica utilizada frequentemente. Seja por exemplo o problema de processar uma
lista de itens de tal maneira que cada item seja operado por uma mesma regra de transformao:
transforma(Lista, F, NovaLista)
onde Lista a lista original, F uma regra de transformao e NovaLista a lista de todos os itens
transformados. O problema de transformar Lista em NovaLista pode ser subdividido em dois casos:
(1) Caso Bsico: Lista = []
Se Lista = [], ento NovaLista = [], independentemente de F.
(2) Caso Geral: Lista = [X | Resto]
Para transformar uma lista do tipo [X | Resto] em uma lista do tipo [NovoX | NovoResto],
transforme Resto, obtendo NovoResto e transforme X, obtendo NovoX.
Em Prolog:
transforma([], _, []).
transforma([X | Resto], F, [NovoX | NovoResto]) :-
G =.. [F, X, NovoX], call(G),
transforma(Resto, F, NovoResto).
A razo pela qual a recurso se aplica to naturalmente em Prolog reside no fato de que os objetos
estruturados, como rvores e listas, possuem uma organizao recursiva intrnseca. Uma lista, por
exemplo, ou vazia (caso bsico), ou possui uma cabea e um corpo (caso geral).
12.2.2 GENERALIZAO
Muitas vezes uma boa idia generalizar o problema original, de forma a permitir que a soluo do
problema generalizado seja formulada recursivamente. O problema original ento solucionado como
um caso especial da verso mais geral. A generalizao de uma relao envolve tipicamente a intro-
duo de um ou mais argumentos extras. O maior problema, que pode requerer uma profunda intui-
o, : "Como encontrar a generalizao correta?". Como ilustrao examinaremos um clssico da
pesquisa em inteligncia artificial que o "problema das oito damas". O enunciado original desse
problema prope dispor oito damas em um tabuleiro de xadrez de maneira que nenhuma delas ataque
as demais. A relao correspondente poderia ser representada por:
oitoDamas(Posio)
que ser verdadeira se Posio representar uma posio do tabuleiro tal que nenhuma dama ataque as
restantes. Uma idia interessante, nesse caso generalizar o nmero de damas de oito para N, de for-
ma que o nmero de damas se torna o argumento adicional.
nDamas(Posio, N)
114
A vantagem dessa generalizao que h uma formulao recursiva imediata para a relao nDa-
mas/2:
(1) Caso Bsico: N = 0
Colocar "zero" damas em segurana trivial.
(2) Caso Geral: N > 0
Para colocar N damas em segurana no tabuleiro necessrio satisfazer as seguintes condi-
es:
Obter uma configurao segura para N - 1 damas, e
Adicionar as damas restantes de forma que nenhuma delas ataque as demais.
Uma vez que o problema generalizado est solucionado, a soluo do problema original imediata:
oitoDamas(Posio) :-
nDamas(Posio, 8).
12.2.3 REPRESENTAO GRFICA DE PROBLEMAS
Na busca por idias para solucionar um dado problema, frequentemente de grande utilidade introdu-
zir alguma representao grfica do mesmo. Um desenho pode ajudar na percepo de algumas rela-
es essenciais do problema. S ento passa-se a descrever o que se v no desenho na linguagem de
programao escolhida. No caso do Prolog, essa tcnica parece ser especialmente produtiva, eis que:
Prolog particularmente adequado para problemas envolvendo objetos e relaes entre objetos.
De modo geral tais problemas podem ser naturalmente ilustrados por meio de grafos, onde os
nodos correspondem a objetos e os arcos a relaes;
Os objetos estruturados em Prolog so naturalmente representados por meio de rvores;
O significado declarativo dos programas Prolog facilita a traduo de representaes grficas
porque, em princpio, a ordem na qual o desenho feito no constitui um fator importante.
12.3 ESTILO DE PROGRAMAO
O propsito de adotar algumas convenes relacionadas ao mtodo ou estilo de programao adotado
fundamentalmente:
Reduzir o risco de erros de programao, e
Produzir programas de boa legibilidade, fceis de entender, corrigir e modificar.
Algumas normas cuja observncia produz um bom estilo de programao em Prolog sero introduzi-
das a seguir: regras gerais, organizao tabular de procedimentos longos e o uso apropriado de co-
mentrios.
12.3.1 REGRAS GERAIS PARA UM BOM ESTILO
As clusulas do programa devem ser curtas. Seu corpo no deve conter mais que uns poucos
objetivos. Empregar sempre
proc1A :- a, b, c.
proc1B :- d, e, f.
proc1C :- g, h, i.
ao invs de
proc1 :- a, b, c, d, e, f, g, h, i.
115
Os procedimentos do programa devem tambm ser curtos (conter poucas clusulas), porque
procedimentos longos demais so difceis de entender. (Apesar disso, procedimentos longos
podem ser aceitveis, desde que possuam uma estrutura uniforme, conforme ser discutido mais
adiante);
Adotar nomes mnemnicos para procedimentos e variveis, indicando o significado das rela-
es e o papel desempenhado pelos objetos que nelas se fazem presentes;
O lay-out dos programas importante, incluindo um bom espacejamento, uso de linhas em
branco, e identao. Clusulas sobre o mesmo procedimento devem ser agrupadas conjunta-
mente. Deve haver linhas em branco entre os procedimentos. Cada objetivo deve ser escrito em
uma nova linha. Segundo Bratko [Bra 86]:
"Programas Prolog muitas vezes lembram poemas, devido ao apelo esttico produzido pelas
idias e formas que contm.".
Convenes de estilo desse tipo podem variar de programa para programa, uma vez que depen-
dem do problema e do gosto de cada programador. importante que as mesmas convenes
sejam usadas de forma consistente em todo o programa;
O operador cut deve ser usado com cuidado. Seu uso deve ser evitado quando no for absolu-
tamente necessrio. Se no for possvel evitar o uso de cuts, melhor usar apenas os cuts "ver-
des" e jamais os "vermelhos". Como foi discutido no captulo 6, um cut "verde" quando pode
ser removido sem alterar o significado declarativo da clusula em que se encontra. Caso contr-
rio o cut "vermelho";
O operador not, devido a sua relao com o cut tambm pode apresentar comportamento ines-
perado. necessrio ter completo conhecimento sobre a forma em que o not definido em
Prolog:
not(P) :- P, !, fail; true.
bem como as consequncias da adoo da hiptese do mundo fechado na execuo da negao
em Prolog (ver captulo 6). Se entretanto estivermos em dvida entre usar o not ou o cut, o pri-
meiro prefervel a alguma construo obscura com o uso do cut;
A modificao do programa por meio dos predicados assert/1 e retract/1 pode degradar em
grande escala a transparncia do seu comportamento. Em particular, um mesmo programa pode
responder a mesma consulta de maneira diferente em momentos diferentes. Em tais casos, se
quisermos reproduzir o mesmo comportamento, temos que nos certificar que todos os estados
anteriores do programa, desde o incio de sua execuo, foram perfeitamente reproduzidos;
O uso do ponto-e-vrgula (correspondendo ao conetivo "ou") pode obscurecer o significado de
uma clusula. A legibilidade pode ser algumas vezes incrementada pela diviso da clusula que
contm o ";" em duas.
Para ilustrar os pontos discutidos at aqui, vamos considerar a seguinte relao:
merge(L1, L2, L3)
onde L1 e L2 so listas ordenadas que so reunidas ordenadamente em L3. Por exemplo:
merge([2, 4, 7], [1, 3, 4, 8], [1, 2, 3, 4, 4, 7, 8])
A implementao abaixo um contra-exemplo de definio da relao merge/3, empregando um es-
tilo que deixa muito a desejar:
merge(L1, L2, L3) :-
L1 = [], !, L3 = L2;
L2 = [], !, L3 = L1;
L1 = [X | Resto1],
L2 = [Y | Resto2],
(X < Y, !, Z = X, merge(Resto1, L2, Resto3);
(Z = Y, merge(L1, Resto2, Resto3)),
L3 = [Z | Resto3].
116
J a verso a seguir possui um estilo muito mais transparente e legvel, alm de ser com certeza mais
eficiente, uma vez que tira partido da unificao dos argumentos correspondentes ao caso bsico na
prpria cabea da clusula:
merge([], L, L).
merge(L, [], L).
merge([X | R1], [Y | R2], [X | R3]) :-
X < Y, !, merge(R1, [Y | R2], R3).
merge(L1, [Y | R2], [Y | R3]) :-
merge(L1, R2, R3).
12.3.2 ORGANIZAO TABULAR DE PROCEDIMENTOS LONGOS
Procedimentos longos podem vir a ser aceitveis, desde que apresentem uma estrutura uniforme. Uma
estrutura uniforme tpica a formada por um conjunto de fatos que efetivamente definem uma relao
em forma tabular. As vantagens de tal organizao so as seguintes:
A estrutura facilmente entendida,
A estrutura incremental: pode ser facilmente refinada pela adio de novos fatos, e
de fcil verificao, correo e modificao (pela simples substituio de algum fato, inde-
pendentemente dos demais).
12.3.3 O USO DE COMENTRIOS
Os comentrios no programa devem, antes de mais nada, explicar a sua finalidade e como deve ser
utilizado. Somente depois disso que devem aparecer os detalhes do mtodo empregado e outras ca-
ractersticas do programa. O propsito inicial dos comentrios facilitar ao usurio o uso do progra-
ma e, se for o caso, a sua modificao. Os comentrios devem descrever, da forma mais sucinta poss-
vel, porm sem perda de informao, tudo o que for essencial para tais finalidades. Um erro muito
comum a produo de programas sub-comentados, entretanto, programas supercomentados tambm
no so desejveis. A explicao de detalhes bvios da codificao de um programa uma carga des-
necessria. Longos trechos de comentrios devem preceder o cdigo ao qual se referem, enquanto que
pequenas notas devem ser intercaladas na prpria codificao. A informao que normalmente deve
ser includa como comentrio compreende o seguinte:
O que o programa faz, como deve ser utilizado, (por exemplo, que tipo de consulta deve ser
formulada e quais so os resultados esperados) e exemplos de utilizao;
Descrio dos predicados de nvel mais alto;
Descrio dos principais conceitos representados;
Tempos de execuo e requisitos de memria;
Limitaes do programa;
Utilizao de recursos especiais dependentes do hardware;
Idem com relao ao software bsico;
Descrio dos predicados do programa;
Detalhes algortmicos e de implementao.
12.4 DEPURAO DE PROGRAMAS
Quando um programa apresenta um comportamento diferente do esperado, o principal problema passa
a ser a localizao do(s) erro(s). mais fcil localizar um erro em uma parte do programa ou mdulo
117
do que no programa inteiro, portanto, um bom princpio de correo de programas comear pelo
teste de pequenas unidades do programa e, quando estas forem consideradas confiveis, passar a testar
mdulos maiores at que o programa inteiro possa ser testado.
A correo de programas em Prolog facilitada por duas circunstncias: primeiro, Prolog uma lin-
guagem interativa, de forma que qualquer parte do programa pode ser ativada diretamente por meio de
uma consulta apropriada; segundo, as implementaes Prolog normalmente oferecem ferramentas
especiais para "debugging". Como resultado desses dois recursos, a correo de programas em Prolog
pode, em geral, ser executada de forma bem mais eficiente do que a maioria das linguagens de pro-
gramao.
A ferramenta bsica para a depurao de programas o processo de "tracing". Sua aplicao a um
objetivo significa que as informaes associadas satisfao desse objetivo iro sendo apresentadas
durante a execuo. Tais informaes incluem:
Informao de Entrada: O nome do predicado e os valores dos argumentos quando o objetivo
disparado;
Informao de Sada: No caso do objetivo ser bem sucedido, so apresentados os valores dos
argumentos que o satisfazem. Em caso contrrio, a indicao de falha no ponto em que esta
ocorreu;
Informao de Reentrada: Na chamada do mesmo objetivo atravs de backtracking.
Entre a entrada e a sada, pode-se obter a mesma informao de todos os sub-objetivos envolvidos, de
forma que podemos dispor do tracing da execuo de qualquer consulta ao programa, desde os nveis
mais elevados at que os fatos correspondentes sejam encontrados. Isso pode, em determinadas cir-
cunstncias, ocasionar um excesso de informao, assim, permitido ao usurio especificar um tra-
cing seletivo. H dois mecanismos dedicados a essa seleo: primeiro, suprimir a informao de tra-
cing alm de determinado nvel; segundo, executar o tracing apenas sobre algum subconjunto espec-
fico de predicados e no sobre o programa inteiro. Tais ferramentas para a depurao de programas
so ativadas por meio de predicados pr-definidos que variam de uma implementao para outra. Um
conjunto tpico desses predicados o seguinte:
trace: Dispara um processo exaustivo de tracing para todos os objetivos que se seguirem;
notrace: Interrompe o processo de tracing;
spy(P): Especifica o nome de uma relao P para o processo de tracing. O predicado spy/1
empregado quando se est particularmente interessado no comportamento da relao
nomeada e se deseja evitar o tracing de outros objetivos (tanto acima quanto abaixo
de P);
nospy(P): Interrompe o tracing da relao P.
O processo de tracing pode ser interrompido alm de uma certa profundidade por meio de comandos
especiais acionados durante a execuo. Dependendo da implementao pode haver ainda diversos
comandos de depurao disponveis, tais como retornar a um determinado ponto anterior da execuo.
Aps tal retorno podemos, por exemplo, repetir a execuo de forma mais detalhada.
12.5 EFICINCIA
H diversos aspectos de eficincia, incluindo os mais comuns: tempo de execuo e consumo de me-
mria de um programa. Um outro aspecto, pouco considerado mas indubitavelmente de grande im-
portncia o tempo consumido no desenvolvimento de um programa. A arquitetura dos computadores
convencionais no especialmente adequada para o estilo de execuo de programas adotado pelo
Prolog - ou seja, a satisfao de uma lista de objetivos. Portanto, as limitaes de espao e tempo a
118
que todas as linguagens de programao esto sujeitas, podem vir a ser sentidas antes pelos programas
Prolog.
Por outro lado, em muitas reas de aplicao, o uso do Prolog vai reduzir consideravelmente o tempo
de desenvolvimento, pois os programas Prolog so em geral mais fceis de escrever, entender e depu-
rar do que os escritos em linguagens convencionais. Problemas que gravitam em torno do "domnio
Prolog" envolvem processamento simblico, no-numrico, sobre objetos estruturados e as relaes
entre eles. Em particular, o uso de Prolog tem sido especialmente bem sucedido em reas envolvendo
a soluo simblica de equaes, planejamento, bases de dados, solucionadores genricos, prototipa-
o, implementao de linguagens de programao, simulao discreta e qualitativa, projeto arquite-
tnico, aprendizado de mquina, interpretao da linguagem natural, sistemas especialistas e diversas
outras reas da inteligncia artificial. Sob outro ngulo, matemtica numrica uma rea na qual os
programas Prolog no conseguem competir.
Com respeito a eficincia na execuo, um programa compilado sempre mais eficiente do que um
programa interpretado, portanto, se o sistema Prolog adotado possui um interpretador e um compila-
dor, este ltimo deve ser usado preferencialmente ao primeiro quando a eficincia se tornar um ponto
crtico. Se um programa se apresenta ineficiente, muitas vezes isso pode ser radicalmente modificado
por meio de alteraes no seu prprio algoritmo, entretanto, para fazer isso, os aspectos procedimen-
tais do programa devem ser considerados. Uma maneira simples de aumentar a eficincia de um pro-
grama encontrar uma ordenao mais adequada para as clusulas no interior dos procedimentos e
para os objetivos no interior das clusulas. Um outro mtodo, relativamente simples, a introduo de
cuts em posies apropriadas. Idias para aumentar a eficincia de um programa normalmente surgem
de um entendimento mais profundo do problema. Um algoritmo mais eficiente resulta de melhorias de
dois tipos:
Aumento na eficincia de busca, evitando backtracking desnecessrio e interrompendo a execu-
o de alternativas inteis o mais cedo possvel, e
Uso de estruturas de dados mais adequadas para a representao de objetos no programa, de
forma que as operaes sobre esses objetos possam ser implementadas de maneira mais efici-
ente.
Esses dois tipos de melhorias sero abordados em maior detalhe nos exemplos apresentados nas pr-
ximas sees.
12.5.1 O PROBLEMA DE COLORIR UM MAPA
O problema de colorir um mapa corresponde a atribuir, a cada pas em um determinado mapa, uma
certa cor, escolhida de um conjunto de quatro cores diferentes, de maneira que dois pases vizinhos
nunca sejam coloridos com a mesma cor. H um teorema que garante que isso sempre possvel de
ser feito. Vamos assumir que o mapa seja especificado pela relao:
viz(Pas, Vizinhos)
onde Vizinhos a lista de todos os pases que possuem alguma fronteira em comum com Pas. Assim,
o mapa da Amrica do Sul, com 13 pases, seria especificado em ordem alfabtica por:
viz(argentina, [bolvia,brasil,chile,paraguai,uruguai]).
viz(bolvia, [argentina,brasil,chile,paraguai,peru]).
viz(brasil, [argentina,bolvia,colmbia,guiana,
guiana_francesa,paraguai,suriname,
uruguai, venezuela]).
...
Uma possvel soluo para o problema das cores de cada pas seria representar a correspondncia
entre estes e suas cores por uma lista de pares do tipo:
Pas/Cor
119
que especifca uma cor para cada pas em um determinado mapa. Para o mapa proposto, os nomes dos
pases so dados antecipadamente e o problema ser encontrar a cor adequada para colorir cada um
deles. Assim, no caso da Amrica do Sul, o problema corresponde a encontrar uma instanciao ade-
quada para as variveis C1, C2, C3, etc. na lista:
[argentina/C1, bolvia/C2, brasil/C3, ...]
Para isso define-se a relao cores/1, cujo nico argumento a lista acima e que ser verdadeira se a
lista satisfizer a restrio do colorido do mapa, com respeito relao viz/2 definida anteriormente.
Sejam as cores escolhidas azul, amarelo, vermelho e verde. A condio de que dois pases vizinhos
no podem ter a mesma cor pode ser formulada em Prolog por:
cores([]).
cores([Pa/Cor | Resto]) :-
cores(Resto),
membro(Cor, [azul, amarelo, vermelho, verde]),
not(membro(Pas1/Cor,Resto),vizinho(Pas,Pas1)).
vizinho(Pas, Pas1) :-
viz(Pas, Vizinhos), membro(Pas1, Vizinhos).
onde membro/2 a relao usual de ocorrncia em listas. O procedimento cores/1 funciona relativa-
mente bem para mapas simples, com poucos pases, entretanto, para mapas complexos como o da
Amrica do Sul, sua eficincia deixar a desejar. Assumindo que o predicado pr-definido setof/3
esteja disponvel, uma tentativa de colorir a Amrica do Sul poderia ser a seguinte: Primeiro define-se
uma relao auxiliar:
pas(P) :- viz(P, _).
Ento uma consulta adequada para colorir a Amrica do Sul poderia ser formulada por:
?-setof(P/Cor, pas(P), Lista), cores(Lista).
O objetivo setof/3 ir primeiro construir uma lista de itens P/Cor, na qual as cores sero representadas
por variveis no-instanciadas. Depois o objetivo cores/1ir produzir a instanciao adequada. pro-
vvel, entretanto, que essa tentativa falhe devido sua ineficincia. Um estudo detalhado de como o
Prolog tenta satisfazer o objetivo cores/1 revela a fonte de tal ineficincia. Os pases em Lista so
organizados em ordem alfabtica, que no tem nada a ver com a sua disposio geogrfica. A ordem
em que as cores so atribudas aos pases corresponde ordem da Lista (comeando pelo final), o que
, no caso em questo, independente da relao viz/2. Assim, o processo de colorir os pases comea
em algum ponto do mapa, continua em um outro extremo, etc, movendo-se de forma mais ou menos
aleatria. Isso pode conduzir facilmente a uma situao na qual um pas que deva ser colorido encon-
tre-se rodeado por outros pases j coloridos com todas as quatro cores disponveis, sendo ento ne-
cessrio acionar o mecanismo de backtracking, com elevado nus para a eficincia do programa.
Fica claro ento que a eficincia depende da ordem na qual os pases sero coloridos. A intuio suge-
re uma estratgia simples de ordenao que apresenta um desempenho muito superior ao mtodo ale-
atrio. Comea-se com algum pas que tenha muitos vizinhos. Depois so coloridos os seus vizinhos.
Depois os vizinhos dos vizinhos e assim por diante. Para a Amrica do Sul, ento, o Brasil (que faz
fronteira com nove pases, parece ser um bom candidato para iniciar o processo. Assim, quando a lista
de Pas/Cor for construda, o Brasil deve ser colocado no fim, com todos os demais pases o antece-
dendo. Dessa forma o algoritmo, que comea a processar a partir do ltimo elemento da lista iniciar
com o Brasil e continuar dali a processar os pases vizinhos como foi explicado anteriormente.
Essa nova ordenao aumenta muito a eficincia do programa em comparao com a ordenao alfa-
btica original, produzindo sem dificuldade os possveis coloridos do mapa da Amrica do Sul.
Pode-se construir manualmente uma lista apropriada dos pases da Amrica do Sul, mas no neces-
srio fazer isso. O procedimento fazLista/1, definido abaixo executar essa tarefa para ns. Ele inicia
a construo com algum pas especificado (Brasil, no nosso caso) e coleta os pases em uma lista de-
nominada "Fechada". Cada pas , inicialmente colocado em outra lista, denominada "Aberta", antes
120
de ser transferido para Fechada. Toda vez que um pas for transferido de Aberta para Fechada, os seus
vizinhos sero colocados em Aberta.
fazLista(Lista) :-
coleta([brasil], [], Lista).
coleta([], Fechada, Fechada).
coleta([X | Aberta], Fechada, Lista) :-
membro(X, Fechada), !,
coleta(Aberta, Fechada, Lista).
coleta([X | Aberta], Fechada, Lista) :-
viz(X, Vizinhos),
conc(Vizinhos, Aberta, Aberta1),
coleta(Aberta1, [X | Fechada], Lista).
onde a relao conc/3 a relao j estudada anteriormente para a concatenao de listas.
12.5.2 APERFEIOANDO AS ESTRUTURAS DE DADOS
Nos programas apresentados at aqui, a concatenao de listas tem sido programada da seguinte ma-
neira:
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
Essa forma de programar a concatenao de listas pode tornar-se bastante ineficiente quando a primei-
ra lista muito longa, uma vez que esta deve ser inteiramente percorrida at que a lista vazia seja
encontrada. Para tornar a relao conc/3 verdadeiramente eficiente, deve-se pular diretamente para o
fim da primeira lista em um nico passo de computao. Isso somente possvel se soubermos locali-
zar o fim de uma lista, o que no pode ser feito a partir da representao adotada at o momento.
necessrio portanto uma nova representao para listas. Uma soluo possvel representar cada lista
por meio de um par de listas. Por exemplo, a lista [a, b, c] pode ser representada por meio de duas
listas:
L1 = [a, b, c, d, e] e L2 = [d, e]
Esse par de listas, que denotaremos por L1-L2, representa a diferena entre L1 e L2. Isso, natural-
mente, s vai funcionar se a lista L2 for um sufixo de L1. Note que a mesma lista pode ser representa-
da por diversos pares-diferena. Por exemplo, a lista [a, b, c] pode ser representada por:
[a, b, c] - []
[a, b, c, d, e] - [d, e]
[a, b, c, d | T] - [d | T]
[a, b, c, | T] - T
...
A lista vazia representada por qualquer par L-L. Como o segundo membro do par indica o final da
lista, este passa a poder ser acessado diretamente. Isso pode ser usado para uma implementao muito
mais eficiente da concatenao de listas. O mtodo proposto ilustrado na figura 12.1 e a correspon-
dente relao em Prolog que denominaremos concat/3 pode ser representada por um nico fato:
concat(A1-Z1, Z1-Z2, A1-Z2)
L1 L2
A1 Z1 A2 Z2
<------------------------------ L3 ------------------------------->
Figura 12.1 Concatenao de listas representadas por pares-diferena
Na figura acima. L1 representada por A1-Z1, L2 por A2-Z2 e o resultado, L3, por A1-Z2, o que
verdadeiro quando Z1=A2. Vamos usar a relao concat/3 para concatenar as listas [a, b, c] (repre-
121
sentada pelo par [a, b, c, | T1] - T1) e [d, e] (representada pelo par [d, e | T2] - T2). A concatenao
obtida pela simples unificao do objetivo proposto na consulta com a clusula que define concat/3.
?-concat([a, b, c | T1] - T1, [d, e | T2] - T2, Lista.
T1 = [d, e | T2]
Lista = [a, b, c, d, e | T2] - T2
12.5.3 DECLARAO DE FATOS INFERIDOS
Algumas vezes, durante a computao, o mesmo objetivo tem que ser satisfeito vrias vezes. Como o
Prolog no possui nenhum mecanismo adequado para identificar essa situao, toda a sequncia de
computaes ser repetida cada vez que o objetivo tiver de ser satisfeito. Como um exemplo, vamos
considerar um programa para computar o ensimo nmero da sequncia de Fibonacci. A sequncia de
Fibonacci :
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
onde cada nmero, com exceo dos dois primeiros, a soma dos dois nmeros anteriores. Definire-
mos um predicado fib(N, F) para computar para um dado nmero N, o ensimo numero F da sequn-
cia de Fibonacci. Contaremos os nmeros da sequncia iniciando com N=1. O programa a seguir trata
inicialmente os dois primeiros nmeros de Fibonacci como casos especiais e depois especifica a regra
geral para a gerao da seqncia.
fib(1, 1).
fib(2, 1).
fib(N, F) :-
N > 2,
N1 is N-1, fib(N1, F1),
N2 is N-2, fib(N2, F2),
F is F1+F2.
Esse programa tende a refazer partes da computao. Isso pode ser facilmente constatado se gerarmos
o tracing da execuo de uma consulta, por exemplo, ?-fib(6, F). A repetio desnecessria de com-
putaes intermedirias pode ser facilmente evitada se o programa "lembrar" cada um dos nmeros de
Fibonacci gerados como resultados parciais. A idia utilizar o predicado pr-definido assert/1 e adi-
cionar esses resultados parciais base de dados na forma de fatos. Esses fatos devem preceder todas
as outras clusulas sobre fib para prevenir o uso da regra geral nos casos em que o resultado j co-
nhecido. O procedimento modificado fibo/2 difere de fib/2 apenas pela incluso de um objetivo adici-
onal:
fibo(1, 1).
fibo(2, 1).
fibo(N, F) :-
N > 2,
N1 is N-1, fibo(N1, F1), N2 is N-2, fibo(N2, F2),
F is F1+F2,
asserta(fibo(N, F)).
Guardar os resultados intermedirios uma tcnica convencional para evitar computaes repetidas.
No caso dos nmeros de Fibonacci podemos evitar essa repetio por meio do uso de outro algoritmo,
diferente do proposto acima. Esse novo algoritmo produzir um programa mais difcil de entender,
porm de execuo mais eficiente. A idia bsica no definir o ensimo nmero de Fibonacci como
a simples soma de seus dois antecessores imediatos, deixando que chamadas recursivas completem o
processamento recuando at os dois primeiros nmeros de Fibonacci. Ao invs disso, podemos traba-
lhar "para frente" comeando com os dois nmeros iniciais e computando os nmeros na seqncia
natural, parando quando o ensimo nmero for encontrado. A maior parte do trabalho executada
pelo procedimento
geraFib(M, N, F1, F2, F)
122
onde F1, F2 e F so respectivamente o (M-1)-simo, o M-simo e o N-simo nmero da seqncia. O
procedimento geraFib/5 encontra uma seqncia de transformaes at atingir uma configurao final
(quando M=N), a partir de uma configurao inicial.
Quando geraFib/5 ativado, todos os argumentos, com exceo de F, devem estar instanciados e M
deve ser menor ou igual a N. O programa fica ento:
fibonacci(N, F) :-
geraFib(2, N, 1, 1, F).
geraFib(M, N, F1, F2, F) :-
M >= N.
geraFib(M, N, F1, F2, F) :-
M < M, ProxM is M+1, ProxF2 is F1+F2,
geraFib(ProxM, N, F2, ProxF2, F).
12.6 PROGRAMAO ITERATIVA
Como foi visto, Prolog uma linguagem recursiva, requerendo portanto uma certa maturidade em
termos de pensamento recursivo por parte de seus programadores. Tambm o backtracking uma
poderosa tcnica para os mais diversos propsitos. Por outro lado, recurso e backtracking so difceis
de combinar, porque a recurso constri estruturas durante chamadas sucessivas que so esquecidas
durante o backtracking, a menos que o predicado assert/1 (ou suas opes) seja empregado para lem-
br-las. Nesse caso porm a execuo do programa produz uma estrutura muito complexa e intrinca-
da.
Esta situao pode ser melhorada com o emprego de algumas tcnicas de programao estruturada.
Nem todos os problemas recursivos o so no sentido profundo da palavra. Alguns so apenas "iterati-
vos" e devem ser reconhecidos como tal. Um predicado pr-definido desenvolvido para executar ite-
rao o repeat/0, que se comporta exatamente como se houvesse sido definido por:
repeat.
repeat :- repeat.
Por exemplo, um lao para executar processamento de entrada e sada poderia assumir a forma se-
guinte:
loop :-
repeat,
read(X),
(X = fim, !; processa(X,Y), write(Y), nl, fail).
Tal procedimento ir ler um termo, process-lo, imprimir alguma sada e falhar, ocasionando por
backtracking a repetio destas operaes at que o termo lido seja "fim".
Considere agora um programa para imprimir todos os elementos de uma lista L. Uma soluo recursi-
va seria:
imprimeLista([]).
imprimeLista([X | Y]) :-
write(X), nl, imprimeLista(Y).
Esse padro de recurso comum em Prolog. Pode-se entretanto generaliz-lo definindo um predica-
do:
for(X, Y) :-
X, Y, fail.
for(X, Y).
de modo que para todas as solues de X, Y ser ativado. O lao produzido pelo predicado for/2 ter-
mina quando no houver mais solues para X. A impresso de todos os elementos de uma lista as-
sumiria ento a forma abaixo:
imprimeLista(L) :-
for(membro(X, L), (write(X), nl)).
123
Um outro exemplo seria o problema de listar todos os nmeros de um a dez. Uma soluo recursiva
seria:
listaNmeros(N) :- N > 10, !.
listaNmeros(N) :-
write(N), nl, N1 is N+1, listaNmeros(N1).
?-listaNmeros(1).
1
2
...
10
Ao invs disso definiremos um predicado in/3 que, por backtracking, retorna com os valores de 1 a N:
in(I, I, H) :-
H >= I.
in(I, L, H) :-
N is L+1, in(I, N, H).
?-for(in(I, 1, 10), (write(I), nl)).
O predicado for/3 pode ser combinado de diversas formas diferentes. Por exemplo, para imprimir
tabelas de multiplicao:
tabMult :-
for(in(I, 1, 10),
(for(in(J, 1, 10),
(K is I*J, out(K))), nl)).
out(X) :-
write(X), write(' ').
Como uma aplicao do conceito acima, e ao mesmo tempo como um exerccio de utilizao de ope-
radores, eis como possvel fazer programas iterativos em Prolog se parecerem com Pascal:
:-op(1110, xfy, do).
:-op(1109, fx, for).
:-op(1108, xfx, to).
:-op(1107, fx, begin).
:-op(700, xfx, ':=').
do1(begin end) :- !.
do1(begin X ; Y) :- !, do1(X), do1(begin Y).
do1(begin X) :- !, do1(X).
do1(X) :- X.
X := Y :- X is Y.
(for X := Y to Z do U) :- for(in(X, Y, Z), do1(U)).
writeln(X) :- write(X), nl.
A partir da definio acima, podemos escrever o seguinte programa para calcular e imprimir os qua-
drados dos nmeros de 1 a 10:
quadrados :-
for I := 1 to 10 do
begin
K := I*I;
writeln(K);
end.
Essa construo, apesar da aparncia, continua sendo um programa em Prolog. Deve-se entretanto
advertir o leitor para no tomar esse exemplo como uma tentativa sria de implementar um interpreta-
dor Pascal em Prolog. Por exemplo, difcil modelar estruturas aninhadas tais como begin-end, por-
que tais constantes so na verdade delimitadores, como os parnteses, e no operadores.
RESUMO
H diversos critrios para a avaliao de programas, entre outros:
Correo;
124
Eficincia;
Transparncia e Legibilidade;
Modificabilidade;
Robustez;
Documentao.
O princpio dos refinamentos sucessivos uma boa maneira de organizar o processo de desen-
volvimento de programas. Em Prolog essa tcnica pode ser tanto aplicada s relaes e algorit-
mos quanto s estruturas de dados;
As seguintes tcnicas frequentemente auxiliam o programador Prolog a encontrar idias para os
refinamentos:
Recurso;
Generalizao;
Uso de Grficos.
de grande utilidade o emprego de convenes de estilo para reduzir o perigo de erros de pro-
gramao e tornar os programas mais fceis de ler, depurar e modificar;
As diferentes implementaes da linguagem Prolog normalmente oferecem ferramentas auxilia-
res para a depurao de programas, dentre as quais o mecanismo de tracing uma das mais
teis;
Maneiras de aumentar a eficincia de programas Prolog so:
Reordenao de objetivos e clusulas;
Controle do backtracking por meio de cuts;
Uso de assert/1 para evitar recomputao;
Uso de algoritmos e estruturas mais eficientes;
Uso de iterao preferivelmente recurso.
EXERCCIOS
12.1 Defina um predicado para inverter o predicado que encontra a soma dos elementos em uma lista
de valores inteiros.
12.2 Defina um programa que registre os elementos de uma lista nomeada como fatos individualmente
numerados. Por exemplo:
enumera(tab, [a, b, p(c), a])
produziria os seguintes fatos:
elem(tab, 1, a).
elem(tab, 2, b).
elem(tab, 3, p(c)).
elem(tab, 4, a).
12.3 Defina a relao adiciona(Lista, Item, NovaLista) para adicionar Item ao final de Lista produzin-
do NovaLista, sendo que tanto Lista quanto NovaLista devem ser representadas por pares-
diferena.
12.4 Defina a relao inverte(Lista, ListaInvertida) onde ambas as listas so representadas por pares-
diferena.
12.5 Defina os operadores e as relaoes necessrias para representar as construes if-then-else e
while-do no estilo Pascal.
125
13. OPERAES SOBRE ESTRUTURAS DE DADOS
Uma questo fundamental da programao como representar objetos complexos, tais como conjun-
tos e implementar operaes eficientes sobre tais objetos. Como foi visto no captulo anterior, a sele-
o da estrutura de dados apropriada essencial para garantir a eficincia de tais operaes. No pre-
sente captulo sero examinadas as estruturas de dados mais frequentemente utilizadas, que pertencem
a trs grandes famlias: listas, rvores e grafos, e diversos exemplos sero desenvolvidos visando
ilustrar o seu uso e adequao.
13.1 CLASSIFICAO EM LISTAS
Classificao uma operao frequentemente necessria em diversos contextos. Uma lista pode ser
classificada desde que haja uma relao de ordem entre os elementos que a compem. Para os prop-
sitos assume-se a relao de ordem representada por
mq(X, Y)
significando que "X maior que Y", independentemente do que significa "maior que". Se os itens da
lista so nmeros, ento a relao mq/2 ser talvez definida por:
mq(X, Y) :- X > Y.
Se os itens da lista so tomos, ento a relao mq pode corresponder, por exemplo, ordem do cdi-
go ASCII correspondente aos caracteres. Vamos considerar que
classifica(Lista, Sada)
denote uma relao onde Lista uma lista de itens e Sada uma lista dos mesmos itens classificados
em ordem crescente, de acordo com a relao mq/2. Desenvolveremos trs definies de tal relao
em Prolog, baseadas em diferentes idias sobre a classificao de listas. A primeira delas bastante
simples, chegando a ser ingnua: Para classificar uma lista Lista:
(1) Encontre dois elementos adjacentes, X e Y, nesta ordem em Lista, tais que mq(X, Y). Troque as
posies de X e Y, obtendo Lista1 e, depois, classifique Lista1;
(2) Se no houver nenhum par de elementos adjacentes, X e Y, nesta ordem em Lista, ento esta j
est classificada.
O propsito da troca das posies dos itens X e Y, que aparecem fora de ordem em Lista que, aps a
troca, a nova lista obtida est mais prxima de ser uma lista classificada.. Aps um determinado n-
mero de trocas de posio, a lista estar completamente ordenada. Esse princpio de classificao
denominado "bubble sort" (ou classificao "blha"). A relao correspondente, bubblesort/2, apre-
sentada abaixo:
bubblesort(Lista, Sada) :-
troca(Lista, Lista1), !, bubblesort(Lista1, Sada).
bubblesort(Sada, Sada).
troca([X, Y | Resto], [Y, X | Resto]) :-
mq(X, Y).
troca([Z | Resto], [Z | Resto1]) :-
troca(Resto, Resto1).
Um outro algoritmo simples de classificao o sort por insero (insert sort), que se baseia na se-
guinte idia: Para classificar uma lista no vazia, L = [X | R]:
(1) Classifique o corpo R da lista L;
(2) Insira a cabea, X, de L no corpo classificado em uma posio tal que a lista resultante esteja classificada.
O resultado a lista completamente classificada. Esse algoritmo representado em Prolog pela rela-
o insertsort/2:
126
insertsort([], []).
insertsort([X | Resto], Sada) :-
insertsort(Resto, Resto1), insere(X, Resto1, Sada).
insere(X, [Y | Sada], [Y | Sada1]) :-
mq(X, Y), !, insere(X, Sada, Sada1).
insere(X, Sada, [X | Sada]).
Os procedimentos de classificao bubblesort/2 e insertsort/2 so simples, porm ineficientes. Dos
dois, o ltimo o mais eficiente, entretanto, o tempo mdio que o insertsort/2 requer para classificar
uma lista de tamanho n cresce proporcionalmente a n
2
. Para listas muito longas, portanto, um algorit-
mo melhor o quicksort/2, baseado na idia abaixo e ilustrado na Figura 13.1. Para classificar uma
lista no vazia, L:
(1) Separe algum elemento X de L e divida o restante em duas listas, denominadas Menor e Maior,
da seguinte maneira: Todos os elementos de L que so maiores do que X pertencem a Maior e
os restantes pertencem a Menor;
(2) Classifique Menor, obtendo Menor1;
(3) Classifique Maior, obtendo Maior1;
(4) A lista completa a concatenao de Menor1 com [X | Maior1].
[5, 3, 7, 8, 1, 4, 7, 6]
[3, 7, 8, 1, 4, 7, 6]
retira X=5
[3,1, 4] [7, 8, 7, 6]
[1. 3, 4] [6, 7, 7, 8]
[3, 7, 8, 1, 4, 7, 6]
todos > 5
classifica
adiciona X
todos =< 5
classifica
concatena
Figura 13.1: Classificando uma lista com o algoritmo quicksort/2
Se a lista a ser classificada estiver vazia, ento o resultado da classificao tambm uma lista vazia.
Uma implementao do quicksort/2 em Prolog apresentada na Figura 13.2. Um detalhe particular
dessa implementao que o elemento X que retirado de L sempre a cabea da lista. O procedi-
mento que divide L em Maior e Menor uma relao de quatro argumentos:
divide(X, L, Maior, Menor)
A complexidade temporal deste algoritmo depende de nossa sorte ao dividirmos a lista a ser classifi-
cada. Se a lista for dividida em duas outras com aproximadamente o mesmo tamanho, ento a com-
plexidade temporal do procedimento ser proporcional a n.log(n), onde n o tamanho da lista a classi-
ficar. Se, ao contrrio, a diviso resultar em duas listas de tamanho muito desigual, ento a complexi-
dade ser da ordem n
2
. Anlises mais acuradas mostram que, felizmente, o desempenho mdio do
algoritmo quicksort/2 se aproxima bem mais da primeira situao do que da segunda.
127
quicksort([X | R], Sada) :-
divide(X, R, Maior, Menor),
quicksort(Menor, Menor1),
quicksort(Maior, Maior1),
conc(Menor1, [X | Maior1], Sada).
divide(X, [], [], []).
divide(X, [Y | R], [Y | Menor], Maior) :-
mq(X, Y), !, divide(X, R, Menor, Maior).
divide(X, [Y | R], Menor, [Y | Maior]) :-
divide(X, R, Menor, Maior).
conc([], L, L).
conc([X | L1], L2, [X | L3]) :-
conc(L1, L2, L3).
Figura 13.2: Uma implementao do algoritmo quicksort/2 em Prolog
13.2 REPRESENTAO DE CONJUNTOS
Uma aplicao usual para listas a representao de conjuntos de objetos, entretanto, tal representa-
o no adequada, uma vez que o teste de ocorrncia de um item em uma lista se mostra relativa-
mente ineficiente como teste de pertinncia de um elemento a um conjunto. O predicado membro(X,
L), que verifica se X membro da lista L, usualmente programado como:
membro(X, [X | _ ]).
membro(X, [_ | Y]) :-
membro(X, Y).
Para encontrar X em uma lista L, esse procedimento percorre a lista elemento por elemento at que X
seja encontrado ou o fim da lista seja atingido. Isso se torna especialmente ineficiente no caso de lis-
tas muito longas. Para a representao de conjuntos h diversas estruturas em rvore que possibilitam
uma implementao muito mais eficiente da relao de pertinncia. Vamos considerar neste ponto as
denominadas "rvores binrias". Uma rvore binria, ou vazia, ou constituda por trs argumentos:
(1) uma raiz,
(2) uma sub-rvore esquerda, e
(3) uma sub-rvore direita.
A raiz pode ser qualquer coisa, mas as sub-rvores devem necessariamente ser rvores. Na Figura
13.3, apresentado um exemplo. A rvore ali mostrada representa o conjunto {a, b, c, d}. Os ele-
mentos do conjunto so armazenados nos nodos da rvore e, normalmente, sub-rvores vazias no so
representadas. Por exemplo, o nodo "b" possui duas sub-rvores que so ambas vazias.
a
b c
d
raiz
sub-rvore
esquerda
sub-rvore
direita
Figura 13.3 Uma rvore binria
H diversas maneiras de se representar uma rvore binria atravs de um termo Prolog. Uma possibi-
lidade simples tornar a raiz da rvore o functor principal do termo e as sub-rvores os seus argu-
mentos. Assim a rvore da Figura 13.3 seria representada pelo termo:
a(b, c(d)).
128
Entre outras desvantagens, essa representao requer um novo functor para cada nodo da rvore. Isso
pode ocasionar problemas, se os nodos, por sua vez, forem objetos estruturados. Uma maneira melhor
e mais usual de representar rvores binrias o seguinte: Emprega-se um smbolo especial para repre-
sentar a rvore vazia e um functor para representar rvores no-vazias a partir de seus trs compo-
nentes (a raiz e as duas sub-rvores). Assumiremos o seguinte:
A rvore vazia ser representada pelo tomo "nil", e
Ser empregado um functor t, de forma que a rvore que possui uma raiz R, uma sub-rvore es-
querda E e uma sub-rvore direita D seja representada pelo termo:
t(E, R, D).
Nessa representao a rvore da Figura 13.3 corresponderia ao termo:
t(t(nil, b, nil), a, t(t(nil, d, nil), c, nil))
Vamos agora considerar a relao de pertinncia para conjuntos, que denominaremos pertence/2. O
objetivo pertence(X,T) verdadeiro se X um nodo da rvore T. A relao pertence/2 pode ser defi-
nida da seguinte maneira:
X pertence a uma rvore T se:
A raiz de T X, ou
X est na sub-rvore esquerda de T, ou
X est na sub-rvore direita de T.
Tais regras podem ser traduzidas diretamente para Prolog, da seguinte maneira:
pertence(X, t(_, X, _)) :- !.
pertence(X, t(E, _, _)) :-
pertence(X, E).
pertence(X, t(_, _, D)) :-
pertence(X, D).
5
3 8
1 4 6 9
7
Figura 13.4: Um dicionrio binrio
Obviamente o objetivo pertence(X, nil) ir falhar para qualquer valor de X. Vamos investigar agora o
comportamento do predicado pertence/2. Considerando a rvore apresentada na Figura 13.3, temos:
?-pertence(X, T).
X=a; X=b; X=c; X=d;
no
onde os valores de X so obtidos por backtracking. Sob o ponto de vista da eficincia, entretanto, o
procedimento pertence/2 to ineficiente quanto o emprego do predicado membro/2. Um aumento
considervel de eficincia poder entretanto ser obtido se houver uma relao de ordem entre os ele-
mentos do conjunto. Ento os dados na rvore podem ser ordenados da esquerda para a direita de
acordo com essa relao de ordem. Dizemos que uma rvore no-vazia t(E, R, D) est ordenada da
esquerda para a direita se:
(1) Todos os nodos na sub-rvore E so menores do que X,
(2) Todos os nodos na sub-rvore D so maiores do que X, e
129
(3) Ambas as sub-rvores esto tambm ordenadas.
Tal rvore binria denominada um "dicionrio binrio". Um exemplo apresentado na Figura 13.4.
13.3 DICIONRIOS BINRIOS
A vantagem da ordenao que, para procurar um objeto em um dicionrio binrio suficiente pes-
quisar no mximo uma sub-rvore. A chave dessa economia, na busca por um elemento X que po-
demos comparar X e a raiz, imediatamente descartando pelo menos uma sub-rvore. Por exemplo, a
pesquisa pelo elemento 6 na Figura 13.4 est indicada em negrito e corresponde ao seguinte:
Comea-se na raiz, 5;
Compara-se 6 com 5, estabelecendo que 6>5;
A pesquisa continua na sub-rvore direita;
Compara-se 6 com 8, estabelecendo que 6<8;
A pesquisa continua na sub-rvore esquerda;
Compara-se 6 com 6, estabelecendo que 6=6;
A pesquisa encerrada com sucesso.
O mtodo de pesquisa em um dicionrio binrio , portanto:
Para encontrar um item X em um dicionrio binrio D:
Se X a raiz de D, ento X j foi encontrado, seno
Se X menor do que a raiz de D, ento X deve ser procurado na sub-rvore esquerda de D, se-
no
Procurar X na sub-rvore direita de D, e
Se D estiver vazio a pesquisa falha.
Essas regras so programadas em Prolog como o procedimento pertence/2, mostrado abaixo na Figura
13.5, onde a relao mq(X, Y) significa que X maior do que Y. Se os itens armazenados na rvore
so numricos, ento a relao simplesmente X > Y.
pertence(X, t(_,X,_)).
pertence(X, t(E, R, _)) :-
mq(R, X), pertence(X, E).
pertence(X, t(_, R, D) :-
mq(X, R), pertence(X, D).
Figura 13.5: Encontrando um item X em um Dicionrio Binrio
O procedimento pertence/2 pode tambm ser empregado para construir um dicionrio binrio. Por
exemplo, a consulta abaixo ir construir um dicionrio binrio D que contm os elementos 5, 3 e 8:
?-pertence(5, D), pertence(3, D), pertence(8, D).
D=t(t(D1, 3, D2), 5, t(D3, 8, D4))
As variveis D1, D2, D3 e D4 so sub-rvores no especificadas, que podem conter qualquer coisa. O
dicionrio que ser construdo ir depender da ordem dos objetivos na consulta.
Um comentrio sobre a eficincia da pesquisa em dicionrios binrios interessante neste ponto. Em
geral a busca por um item em um dicionrio binrio bem mais eficiente do que em uma lista. Tal
eficincia devida ao seguinte: Vamos supor que n seja o nmero de itens em nosso conjunto de da-
dos. Se o conjunto representado por uma lista. ento o tempo esperado de pesquisa proporcional
ao tamanho n da lista. Em mdia iremos pesquisar a lista at a metade para encontrar um determinado
item, se os valores tiverem uma distribuio normal. Agora, se o conjunto for representado por um
dicionrio binrio, o tempo de procura ser proporcional "altura" da rvore, representada pelo maior
caminho entre a raiz e uma folha da rvore, dependendo portanto de sua conformao.
Diz-se que uma rvore binria (aproximadamente) balanceada se, para cada nodo da rvore, as duas
130
sub-rvores so (aproximadamente) do mesmo tamanho, isto , acomodam o mesmo nmero de itens.
Se um dicionrio de n nodos balanceado de maneira tima, ento sua altura proporcional a log(n).
Pode-se dizer ento que uma rvore balanceada possui complexidade logartmica. A diferena entre n
e log(n) o ganho de eficincia que um dicionrio binrio possui sobre uma lista. Isso vale entretanto
somente quando a rvore for aproximadamente balanceada. Se a rvore se afasta de uma conformao
balanceada, ento o seu desempenho ir degradar. Em casos extremos, de rvores completamente
desbalanceadas, uma rvore fica reduzida a uma lista, tanto em conformao quanto em desempenho.
13.4 INSERO E REMOO DE ITENS EM DICIONRIOS BINRIOS
Na manuteno de um conjunto dinmico de dados, pode-se desejar inserir novos dados ou remover
dados desatualizados do conjunto. Assim, um repertrio comum de operaes sobre um conjunto S de
dados dado na tabela abaixo:
RELAO SIGNIFICADO
pertence(X, S) X pertence a S
inserir(S, X, S1) Inserir X em S produzindo S1
remover(S, X, S1) Remover X de S produzindo S1
A relao pertence/2 foi definida na seo anterior. Definiremos agora a relao insere/3. mais fcil
inserir novos dados no nvel mais "alto" de uma rvore, de modo que um novo item se torna uma "fo-
lha" da rvore em uma posio tal que a ordenao da rvore seja preservada. Representaremos esse
tipo de insero por:
insFolha(D, X, D1)
cujas regras so as seguintes:
O resultado da insero de X a uma rvore vazia a rvore t(nil,X,nil);
Se X a raiz de D, D1=D (itens duplicados no so inseridos);
Se a raiz de D maior do que X, ento X deve ser inserido na sub-rvore esquerda de D. Caso
contrrio X deve ser inserido na sub-rvore direita de D.
Na Figura 13.6, as rvores correspondem a seguinte sequncia de inseres:
insFolha(D1, 6, D2),
insFolha(D2, 7, D3),
insFolha(D3, 4, D4).
para a relao insFolha/3, definida pelo procedimento abaixo:
insFolha(nil, X, t(nil, X, nil)).
insFolha(t(E, X, D), X, t(E, X, D)).
insFolha(t(E, R, D), X, t(E1, R, D)) :-
mq(R, X), insFolha(E, X, E1).
insFolha(t(E, R, D), X, t(E, R, D1)) :-
mq(X, R), insFolha(D, X, D1).
Vamos agora considerar a operao remover/3. fcil remover uma folha, mas a remoo de um nodo
mais complicada. A remoo de uma folha pode, na verdade, ser definida como o inverso da inser-
o, isto :
remFolha(D1, X, D2) :-
insFolha(D2, X, D1).
131
5
3 8
5
3 8
6
5
3 8
5
3 8
6 6
7 7
D1 D2
D3 D4
4
Figura 13.6: Insero ao nvel de folha em um dicionrio binrio
Entretanto, se X um nodo interno, isso no vai funcionar, devido ao problema ilustrado na Figura
13.7: X tem duas sub-rvores, E e D. Aps a remoo de X ficamos com uma lacuna na rvore e E e D
ficam desconectadas do restante dela, sem possibilidade de se conectarem ao nodo pai de X, A, uma
vez que este pode somente acomodar uma delas.
A
X
E D
A
?
E D
remove X
------------------------>
Figura 13.7: O problema de remover um nodo interior em um dicionrio binrio
Se uma das duas sub-rvores, E ou D, estiver vazia, ento a soluo simples: A sub-rvore no-vazia
conectada a A. Se ambas forem no-vazias, ento uma idia a seguinte: O nodo mais esquerda de
D, digamos Y, removido de sua posio e conduzido a ocupar a lacuna deixada por X. Aps esta
transferncia, a rvore resultante continuar ordenada. Naturalmente a mesma idia funciona simetri-
camente, com a transferncia do nodo mais direita de E. De acordo com essas consideraes, a ope-
rao de remover um item de um dicionrio binrio pode ser programada conforme mostrado na
Figura 13.8. A transferncia do nodo mais esquerda da sub-rvore direita realizada pela relao:
trans(T, Y, T1)
onde Y o nodo mais esquerda de T e T1 T aps remover Y.
H ainda uma outra soluo, mais elegante, para as relaes de insero e remoo de nodos. Uma
relao insere/3 pode ser definida, de forma no-determinstica, de maneira que um novo item seja
inserido em qualquer nvel da rvore e no apenas como um nodo folha. As regras correspondentes
so:
Para inserir um nodo X em um dicionrio binrio D:
Inserir X como raiz de D, ou
132
remove(t(nil, X, D), X, D).
remove(t(E, X, nil), X, E).
remove(t(E, X, D), X, t(E, Y, D1)) :-
trans(D, Y, D1).
remove(t(E, R, D), X, t(E1, R, D)) :-
mq(R, X)), remove(E, X, E1).
remove(t(E, R, D), X, t(E, R, D1)) :-
mq(X, R), remove(D, X, D1).
trans(t(nil, Y, D), Y, D).
trans(t(E, R, D), Y, t(E1, R, D)) :-
trans(E, Y, E1).
Figura 13.8: Removendo um nodo interior em um dicionrio binrio
Se a raiz de D maior do que X, ento inserir X na sub-rvore esquerda de D. Caso contr-
rio inserir X na sub-rvore direita de D.
A dificuldade aqui a insero de X como raiz de D. Vamos formular essa operao como a relao:
insRaiz(D, X, D1)
onde X o item a ser inserido como raiz de D e D1 o dicionrio resultante, com X como raiz. A
figura 13.9 ilustra as relaes entre X, D e D1.
Y
E D
X
E1 Y
X
Y D1
E2 D E D2
ou
Figura 13.9: Insero de um item X como raiz de um dicionrio binrio
A questo agora : O que so as sub-rvores E1 e E2 na figura 13.9? (ou D1 e D2, altenativamente). A
resposta deriva das seguintes restries:
E1 e E2 devem ser, necessariamente, dicionrios binrios;
O conjunto de nodos em E1 e E2 igual ao conjunto de nodos em E;
Todos os nodos em E1 so menores do que X e todos os nodos em E2 so maiores do que X.
A relao que impe todas essas restries exatamente a relao procurada, insRaiz/3. Assim, se X
foi inserido em E como raiz, ento as sub-rvores resultantes so E1 e E2 que, em Prolog, devem sa-
tisfazer a:
insRaiz(E, X, t(E1, X, E2))
assim como se X for inserido em D, D1 e D2 devem respeitar:
insRaiz(D, X, t(D1, X, D2))
A Figura 13.10 apresenta o programa completo para a insero no-determinstica em um dicionrio
binrio. A caracterstica principal de tal programa que no h restrio quanto ao nvel de insero.
Assim, insere/3 pode ser empregada na direo inversa para a remoo de um item do dicionrio.
133
insere(DB, X, DB1) :-
insRaiz(DB, X, DB1).
insRaiz(nil, X, t(nil, X, nil)).
insRaiz(t(E, X, D), X, t(E, X, D)).
insRaiz(t(E, Y, D), X, t(E1, X, t(E2, Y, D))) :-
mq(Y, X), insRaiz(E, X, t(E1, X, E2)).
insRaiz(t(E, Y, D), X, t(t(E, Y, D1), X, D2)) :-
mq(X, Y), insRaiz(D, X, t(D1, X, D2)).
Figura 13.10: Insero no-determinstica em um dicionrio binrio
13.5 APRESENTAO DE RVORES
Como todos os objetos em Prolog, uma rvore binria pode ser apresentada por meio do predicado
embutido write/1. Entretanto o objetivo write(T) ir apresentar toda a informao contida em T, sem
indicar graficamente a real estrutura de uma rvore. Pode ser bastante cansativo imaginar a estrutura
de uma rvore a partir do termo Prolog que a representa. Assim muitas vezes desejvel se dispor de
um procedimento que permita a representao grfica de sua estrutura.
H um mtodo relativamente simples de apresentar graficamente a estrutura de rvores binrias. O
truque apresentar a rvore da esquerda para a direita, e no da raiz para as folhas, como so usual-
mente representadas. Vamos definir um procedimento, apresenta(T) para apresentar desse modo a
estrutura de uma rvore T. O princpio o seguinte:
Para apresentar uma rvore no-vazia T:
Apresentar a sub-rvore esquerda de T, identada por alguma distncia, H, para a direita,
Apresentar a raiz de T, e
Apresentar a sub-rvore direita de T, identada por alguma distncia, H, para a direita.
A distncia de identao, H, que pode ser adequadamente escolhida, um parmetro adicional para a
identao de rvores. Pela introduo de H, precisamos de um procedimento, ap(T, H), para apresen-
tar T identada H espaos a partir da margem esquerda. A relao entre os procedimentos apresenta/1 e
ap/2 a seguinte:
apresenta(T) :- ap(T, H).
A Figura 13.11 mostra o procedimento apresenta/1 codificado em Prolog. O princpio adotado para
obter esse formato de sada pode ser facilmente adaptado para a apresentao dos mais diversos tipos
de rvores.
apresenta(T) :- ap(T, 0).
ap(nil, _).
ap(t(E, R, D), H) :-
H2 is H+2,
ap(D,H2),
tab(H), write(R), nl,
ap(E,H2).
Figura 13.11: Apresentao de uma rvore Binria
13.6 GRAFOS
13.6.1 REPRESENTAO
As estruturas em forma de grafos so empregadas em diversas aplicaes, tais como a representao
134
de relaes, situaes e problemas. Um grafo definido por um conjunto de nodos e um conjunto de
arestas, onde cada aresta interliga um par de nodos. Quando as arestas so direcionadas, so tambm
denominadas arcos. Os arcos so representados por meio de pares ordenados. Os grafos assim consti-
tudos so denominados grafos direcionados. Aos arcos podem ser associados custos, nomes ou qual-
quer tipo de rtulo, dependendo da aplicao. Na figura 13.12 so apresentados exemplos de grafos.
b
a c
d
t
s v
u
3
1
2
5
2
(a) (b)
Figura 13.12: (a) Grafo. (b) Grafo direcionado com custos associados aos arcos
Os grafos podem ser representados em Prolog de diversas maneiras. Um mtodo representar cada
aresta ou arco separadamente, por meio de uma clusula. Por exemplo, os grafos da figura acima po-
dem ser representados pelos seguintes conjuntos de clusulas:
conecta(a, b). arco(s, t, 3).
conecta(b, c). arco(t, u, 5).
conecta(c, d). arco(t, v, 1).
conecta(d, b). arco(v, u, 2).
arco(u, t, 2).
Um outro mtodo representar o grafo completo, como um nico objeto. Um grafo pode ser ento
representado por um par de conjuntos: nodos e arcos. Vamos escolher o functor grafo/2 para combinar
esses conjuntos em um par, e o functor ar/2 para as arestas. Ento o grafo da Figura 13.12(a) pode ser
representado por:
G1 = grafo([a,b,c,d],[ar(a,b),ar(b,c),ar(b,d),ar(c,d)])
Para representar um grafo direcionado escolheremos os functores grd/2 para o grafo e a/3 para os
arcos. A representao do grafo direcionado apresentado na Figura 13.12(b) fica ento:
G2 = grd([s,t,u,v],[a(s,t,3),a(t,v,1),a(t,u,5),a(u,t,2), a(v,u,2)])
Se cada nodo estiver conectado a pelo menos um outro nodo - isto : no h nodos "soltos" - o grafo
denominado "conexo". Na representao de grafos conexos pode-se omitir a lista de nodos, uma vez
que esta fica implicitamente definida pela lista de arestas.
Ainda um outro mtodo para representar grafos em Prolog associar a cada nodo a lista de todos os
nodos que lhe so adjacentes. Nessa representao um grafo uma lista de pares constitudos por um
nodo e a sua correspondente lista de nodos adjacentes. Os grafos anteriormente exemplificados podem
ento ser representados por:
G1 = [a [b], b [a, c, d], c [b, d], d [b, c]]
G2 = [s [t/3], t [u/5, v/1], u [t/2], v [u/2]]
onde os smbolos "" e "/" so operadores infixos.
A representao mais adequada vai naturalmente depender da aplicao e das operaes que devero
ser executadas sobre os grafos. Duas operaes tpicas so:
Encontrar um caminho entre dois nodos dados, e
Encontrar um subgrafo com alguma propriedade caracterstica.
135
13.6.2 CAMINHAMENTO EM GRAFOS
Seja G um grafo e A e Z dois nodos de G> Vamos definir uma relao
caminho(A, Z, G, C)
onde C um caminho acclico entre A e Z em G. O caminho C representado por uma lista de nodos.
Se G o grafo representado na Figura 13.12(a), ento podemos escrever, por exemplo:
caminho(a, d, G, [a, b, d])
caminho(a, d, G, [a, b, c, d])
Uma vez que o caminho no deve conter nenhum ciclo, cada nodo pode aparecer na lista no mximo
uma vez. Um mtodo para se encontrar um caminho entre dois nodos em um grafo o seguinte:
Para encontrar um caminho acclico C entre os nodos A e Z de um grafo G:
Se A = Z, ento C = [A], seno
Encontrar um caminho acclico C1, de algum nodo Y at o nodo Z e encontrar um cami-
nho de A at Y, evitando os nodos em C1.
Essa formulao implica em outra relao: Encontre um caminho sob a restrio de evitar um deter-
minado conjunto de nodos. Assim, definiremos um segundo procedimento:
caminho1(A, C1, G, C)
cuja relao com o procedimento caminho/4 mostrada na Figura 13.13 a seguir:
A X
<----------------- caminho1 ----------------->
<---------------------------------------------- caminho1 -------------------------------------------------->
Y Z ... ... ...
Figura 13.13: Relao entre os procedimentos caminho/4 e caminho1/4
Como ilustrado na Figura 13.13, os argumentos do procedimento caminho1/4 so:
A, que um nodo,
G, que um grafo,
C1, que um caminho acclico em G, e
C, que um caminho acclico em G, de A at o incio de C1 e continuando ao longo de C1 at o
seu final.
A relao entre caminho/4 e caminho1/4 dada por:
caminho(A, Z, G, C) caminho(A, [Z], G, C).
A Figura 13.13 sugere uma definio recursiva de caminho1/4. O caso bsico surge quando o nodo
inicial de C1 (Y, na figura) coincide com o nodo inicial de C, que A. Se isso no ocorrer, ento deve
haver um nodo X tal que:
(1) Y adjacente a X,
(2) X no est em C1, e
(3) C satisfaz a caminho1(A, [X | C1], G, C)
O programa completo apresentado na Figura 13.14, abaixo, onde membro/2 a relao de ocorrn-
cia para listas e a relao adjacente(X, Y, G) significa que h um arco conectando os nodos X e Y no
grafo G.
caminho(A, Z, G, C) :-
136
caminho1(A, [Z], G, C).
caminho1(A, [A | C1], _, [A | C1]).
caminho1(A, [Y | C1], G, C) :-
adjacente(X, Y, G),
not membro(X, C1),
caminho1(A, [X, Y | C1], G, C).
adjacente(X, Y, grafo(Nodos, Arestas)) :-
membro(ar(X, Y), Arestas);
membro(ar(Y, X), Arestas).
Figura 13.14: Encontrando caminhos acclicos entre os nodos A e Z no grafo G
Um problema clssico sobre estruturas em grafo encontrar um caminho "hamiltoniano", isto , um
caminho acclico que percorra todos os nodos do grafo. Usando o procedimento caminho/4, anterior-
mente definido, isso pode ser realizado da maneira apresentada abaixo, onde nodo(N, Grafo) significa
que N um nodo do grafo Grafo.
hamiltoniano(Grafo, Caminho) :-
caminho( _, _, Grafo, Caminho),
cobre(Caminho, Grafo).
cobre(Caminho, Grafo) :-
not(nodo(N, Grafo), not membro(N, Caminho).
Pode-se associar custos aos caminhos em um grafo. O custo total de um caminho a soma dos custos
associados aos arcos que formam o caminho. Se no h custos associados aos arcos, ento pode-se
falar sobre a "extenso" do caminho, contando uma unidade para cada um dos arcos que o constituem.
As relaes caminho/4 e caminho1/4 podem ser modificadas de modo a manipular os custos, por meio
da introduo de um argumento adicional para cada caminho:
caminho(A, Z, G, C, Custo)
e
caminho1(A, C1, Custo1, G, C, Custo)
onde Custo o custo do caminho C e Custo1 o custo do caminho C1. A relao adjacente/5 tam-
bm resultado da adio de um argumento extra - o custo de um arco - relao original adjacente/4.
A Figura 13.15 mostra um programa que computa caminhos e os seus custos, podendo ser utilizado
para encontrar um "caminho de custo mnimo" entre dois nodos de um grafo. Isso obtido por meio
dos objetivos:
?-caminho(n1, n2, G, CaminhoMin, CustoMin),
not(caminho(n1, n2, G, _, Custo), Custo < CustoMin).
caminho(A, Z, G, C, Custo) :-
caminho1(A, [Z], 0, G, C, Custo).
caminho1(A, [A | C1], Custo1, G, [A | C1], Custo1).
caminho1(A, [Y | C1], Custo1, G, C, Custo) :-
adjacente(X, Y, CustoXY, G),
not membro(X, C1),
Custo2 is Custo1+CustoXY,
caminho1(A, [X, Y | C1], Custo2, G, C, Custo).
Figura 13.15: C um caminho acclico de A a Z em G cujo custo Custo
De modo semelhante tambm possvel encontrar um "caminho de custo mximo" entre qualquer par
de nodos em um grafo G atravs da conjuno de objetivos abaixo:
?-caminho(_, _, G, CaminhoMax, CustoMax),
not(caminho(_, _, G, _, Custo), Custo > CustoMax).
Deve-se ressaltar que esse mtodo de encontrar caminhos de custo mnimo ou mximo extrema-
mente ineficiente, uma vez que investiga todos os caminhos possveis de forma completamente no
seletiva, sendo totalmente inadequado para grandes grafos, devido sua elevada complexidade tempo-
ral.
137
13.6.3 RVORES GERADORAS
Como j foi comentado, um grafo dito ser conexo se h um caminho entre quaisquer dois nodos que
dele fazem parte. Seja G = (N, A) um grafo conexo com um conjunto de nodos N e um conjunto de
arestas A. Uma "rvore geradora" de G um grafo conexo T = (N, A'), onde A' um subconjunto de
A tal que:
(1) T conexo, e
(2) No h ciclos em T.
Essas duas condies garantem que T uma rvore. Para o grafo apresentado na Figura 13.12(a), por
exemplo, h trs rvores geradoras que correspondem s seguintes trs listas de arestas:
T1 = [a-b, b-c, c-d]
T2 = [a-b, b-d, d-c]
T3 = [a-b, b-d, b-c]
onde cada termo da forma X-Y denota uma aresta entre os nodos X e Y. Pode-se escolher qualquer
nodo na lista para raiz da rvore. As rvores geradoras so de interesse, por exemplo, em problemas
de comunicao, porque fornecem, com o menor nmero de linhas de comunicao possvel, um ca-
minho entre qualquer par de nodos. Definiremos um procedimento:
arvG(T, G)
onde T uma rvore geradora de G. Assumiremos para isso que G um grafo conexo. Podemos ima-
ginar a construo algortmica de uma rvore geradora da seguinte maneira: Iniciamos com um con-
junto vazio de arestas, ao qual gradualmente vamos adicionando arestas de G, tomando cuidado para
que nunca seja gerado um ciclo, at que mais nenhuma aresta de G possa ser adicionada ao conjunto,
porque isso determinaria a gerao de um ciclo. O conjunto de arestas resultante define uma das rvo-
res geradoras de G. A condio de no-ciclo pode ser mantida por meio de uma regra simples: Uma
aresta pode ser adicionada ao conjunto somente se um de seus nodos j pertence rvore geradora em
formao e o outro ainda no pertence. Um programa que implementa essa idia mostrado na Figura
13.11. A relao fundamental ali desenvolve(T1, T, G), onde todos os trs argumentos so conjuntos
de arestas. G um grafo conexo. T1 e T so subconjuntos de G tais que ambos representam rvores. T
uma rvore geradora de G, obtida pela adio de zero ou mais arestas de G a T1. Pode-se dizer que
T1 origina o desenvolvimento de T.
interessante desenvolver tambm um programa para a construo de rvores geradoras de forma
completamente declarativa, pelo simples estabelecimento de relaes matemticas. Assumiremos que
tanto grafos conexos como rvores sejam representados por meio de listas de arestas como no pro-
grama da Figura 13.16. As definies necessrias so:
(1) T uma rvore geradora de G se:
T um subconjunto de G,
T uma rvore, e
T "cobre" G, isto , todo nodo de G est tambm em T.
(2) Um conjunto de arestas T uma rvore se:
T conexo, e
T no possui ciclos.
Usando a relao caminho/4, definida na seo anterior, tais definies podem ser estabelecidas em
Prolog conforme mostrado na figura 13.17. Deve-se notar, entretanto, que o programa ali definido
de pequeno interesse prtico devido a sua ineficincia.
138
arvG(G, T) :-
membro(Aresta, G),
desenvolve([Aresta], T, G).
desenvolve(T1, T, G) :-
novaAresta(T1, T2, G),
desenvolve(T2, T, G).
desenvolve(T, T, G) :-
not novaAresta(T, _, G).
novaAresta(T, [A-B | T], G) :-
adjacente(A, B, G),
nodo(A, T),
not nodo(B, T).
adjacente(A, , G) :-
membro(A-B, G); membro(B-A, G).
nodo(A, G) :-
adjacente(A, _, G).
Figura 13.16: Um procedimento algortmico para obter a
rvore geradora T de um grafoG, assumido conexo
arvG(G, T) :-
subconj(G, T),
rvore(T),
cobre(T, G).
rvore(T) :-
conexo(T),
not temCiclos(T).
conexo(T) :-
not(nodo(A,T), nodo(B,T), not caminho(A,B,T, _)).
temCiclos(T) :-
adjacente(A,B,T),
caminho(A,B,T, [A, X, Y | _]).
cobre(T, G) :-
not(nodo(A, G), not nodo(A, T)).
subconj([], []).
subconj([X | L], S) :-
subconj(L, L1),
(S = L1; S = [X | L1]).
Figura 13.17: Um procedimento declarativo para obter as rvores geradoras de G
RESUMO
No presente captulo estudou-se diferentes mtodos de classificao de listas, tecendo conside-
raes acerca da sua eficincia:
(1) bubblesort/2;
(2) insertsort/2;
(3) quicksort/2.
Representao de conjuntos como rvores binrias e dicionrios binrios:
(1) Procura por um item em uma rvore;
(2) Insero de itens;
(3) Remoo de itens;
(4) Balanceamento de rvores e sua relao com a eficincia;
(5) Apresentao de rvores.
Grafos:
139
(1) Representao de grafos;
(2) Caminhamento em grafos;
(3) Obteno das rvores geradoras de um grafo.
EXERCCIOS
13.1 Escreva um programa para intercalar duas listas classificadas, produzindo uma terceira lista,
tambm classificada. Por exemplo:
?-intercala([3,4,5], [1,2,2,5,7], L).
L = [1,2,2,3,4,5,5,7]
13.2 Escreva um programa para descrever a relao quicksort/2, empregando pares-diferena na repre-
sentao de listas.
13.3 O programa quicksort/2, apresentado neste captulo, possui um desempenho sofrvel quanta a
lista a ser classificada j est classificada ou quase classificada. Analise porque isso ocorre e
proponha modificaes no algoritmo capazes de solucionar tal problema.
13.4 Um outro algoritmo de classificao de listas baseia-se na seguinte proposta: Para classificar uma
lista L:
(1) Divida L em duas listas, L1 e L2, com aproximadamente o mesmo tamanho,
(2) Classifique L1 e L2, obtendo S1 e S2, e
(3) Intercale S1 e S2, obtendo a lista L classificada.
Implemente este princpio de classificao e compare sua eficincia com a obtida no programa
quicksort/2.
13.5 Defina os predicados:
arvBin(Objeto) e dicBin(Objeto)
para reconhecer, respectivamente se Objeto uma rvore binria ou um dicionrio binrio.
13.6 Defina o procedimento
altura(rvoreBinria, Altura)
para computar a altura de uma rvore binria. Assuma que a altura de uma rvore vazia zero e
que a de uma rvore com um nico elemento 1.
13.7 Defina a relao
lineariza(rvore, Lista)
para representar uma rvore linearizada sob a forma de lista.
13.8 Considere as rvores geradoras de um grafo que possui custos associados s arestas. Seja o custo
de uma rvore geradora definido como a soma dos custos de todas as arestas nela presentes. Es-
creva um programa para encontrar a rvore geradora de custo mnimo em um grafo.
140
14. ESTRATGIAS PARA A SOLUO DE PROBLEMAS
O presente captulo introduz um esquema genrico para a soluo de problemas denominado "espao
de estados". Um espao de estados um grafo cujos nodos correspondem a possveis situaes de um
problema, de modo que sua soluo reduzida, em tal representao, procura de um caminho sobre
tal grafo. Estudaremos exemplos de formulao de problemas usando a abordagem do espao de esta-
dos e discutiremos mtodos gerais para a soluo de problemas representados por meio desse forma-
lismo. A soluo de problemas envolve, portanto, a pesquisa em grafos e, tipicamente, a lidar com
alternativas. As estratgias bsicas apresentadas neste captulo para a explorao de alternativas so a
pesquisa em profundidade (depth-first search) e a pesquisa em amplitude (breadth-first search).
14.1 CONCEITOS BSICOS
Vamos considerar o exemplo apresentado na Figura 14.1. O problema formular um planejamento
para reorganizar uma pilha de blocos sobre uma mesa da maneira mostrada na figura, obedecendo as
seguintes trs regras:
(1) Pode-se mover somente um bloco de cada vez;
(2) Um bloco pode ser movido somente se no houver nada sobre ele;
(3) Os blocos somente podem ser colocados diretamente na mesa ou sobre algum outro bloco.
B
A
C
C
B
A
Figura 14.1 O problema da reorganizao dos blocos A, B, C
Deve-se observar que o objetivo no apenas obter a situao final desejada. O que se quer realmente
o "plano" que nos permite alcan-la. Para isso necessrio descobrir uma seqncia de operaes
que permita realizar a transformao proposta.
Podemos pensar neste problema como um caso de explorao entre alternativas. Na situao inicial,
existe apenas uma possibilidade: colocar o bloco C na mesa. Aps fazer isto, surgem trs alternativas
possveis:
Colocar o bloco A na mesa, ou
Colocar o bloco A sobre o bloco C, ou
Colocar o bloco C sobre o bloco A.
Como o exemplo ilustra, dois conceitos devem ser considerados nesse tipo de problema:
(1) As situaes do problema, e
(2) Os movimentos ou aes vlidas que transformam uma situao em outra.
As situaes e os movimentos possveis formam um grafo direcionado, denominado "espao de esta-
dos". Um espao de estados para o problema exemplificado apresentado na Figura 14.2. Os nodos
do grafo correspondem a situaes do problema e os arcos correspondem a transies legais entre os
141
estados. Encontrar um plano cuja execuo solucione o problema original equivalente a encontrar
um caminho entre a situao inicial dada (o nodo inicial) e alguma situao final especificada, tam-
bm denominada "o nodo objetivo".
A B C
B
A C
C
B
A
C
A B
B
C
A
A
B C
A
B C
C
A
B
B
C
A
B
A C
C
A B
A
B
C
A
C
B
Figura 14.2: O espao de estados do problema da reorganizao de A, B e C
A Figura 14.3 apresenta um outro exemplo do mesmo tipo de problema: o "jogo do oito" e a sua re-
presentao reduzida ao problema de caminhamento em um grafo. O jogo do oito um clssico da
pesquisa em inteligncia artificial e consiste em oito peas deslizantes, numeradas de 1 a 8 e dispostas
em uma matriz 3x3 de nove casas. Uma das casas est sempre vazia e qualquer pea a ela adjacente
pode ser movida para essa casa. Podemos imaginar que a casa vazia pode "mover-se", trocando de
lugar com qualquer uma das peas adjacentes. A situao final algum arranjo especial das peas,
como pode ser visto na Figura 14.3.
1 3
8 4 2
7 6 5
1 2 3
8 4
7 6 5
1 3
8 4 2
7 6 5
1 3
8 4 2
7 6 5
1 2 3
8 4
7 6 5
1 3 4
8 5 2
7 6
1 3
8 4 2
7 6 5
1 3 4
8 2
1 3 4
8 2
7 6 5
7 6 5
Figura 14.3: O "jogo do oito" em uma particular configurao
fcil construir aplicaes grficas similares para outros quebra-cabeas populares que se enquadram
no mesmo tipo de problema como, por exemplo, o problema das torres de Hani, ou de como conduzir
a raposa, o ganso e o milho atravs do rio. Neste ltimo problema h um bote que somente pode con-
duzir o fazendeiro e algum outro objeto. O fazendeiro tem que proteger o ganso da raposa e o milho
do ganso. Muitos problemas prticos tambm se encaixam nesse mesmo paradigma, dentre os quais
142
talvez o mais importante seja o "problema do caixeiro-viajante", que modelo formal de diversas
aplicaes prticas. Este problema definido por um mapa com n cidades interligadas por diversas
rodovias. A idia encontrar a rota mais curta, partindo de alguma cidade inicial, visitando todas as
demais cidades e retornando ao ponto de partida. Nenhuma cidade, com exceo da inicial, pode apa-
recer duas vezes no trajeto. O problema pode ser facilmente solucionado atravs de uma adaptao
dos procedimentos de caminhamento em grafos estudados no captulo 13.
Vamos resumir os conceitos introduzidos nestes exemplos. O espao de estados de um dado problema
especifica "as regras do jogo". Os nodos no espao de estados correspondem a situaes possveis e
os arcos correspondem a movimentos vlidos ou "passos de soluo". Um problema particular pode
ser definido por:
Um espao de estados,
Um nodo inicial, e
Uma condio-objetivo, isto , a situao a ser atingida. Denomina-se nodos-objetivos aos no-
dos que satisfazem essa condio.
Podemos associar custos s aes vlidas de um espao de estados. Por exemplos, custos associados
movimentao, no problema de organizao de blocos, indicariam que alguns blocos so mais difceis
de mover do que outros. No problema do caixeiro-viajante, os movimentos correspondem a viagens
diretas entre duas cidades. Ali os custos dos movimentos podem corresponder a distncias entre as
cidades envolvidas.
Nos casos em que temos custos associados aos movimentos, estaremos normalmente interessados em
obter as solues de menor custo possvel. O custo total de uma soluo a soma de todos os custos
associados aos que compem o caminho entre o nodo inicial e o nodo objetivo. Mesmo que no haja
custos, iremos sempre nos deparar com um problema de otimizao: qual o caminho mais curto entre
esses dois pontos?
Antes de apresentar alguns programas que implementam algoritmos clssicos para a pesquisa em es-
paos de estados, vamos estudar como um espao de estados pode ser representado em Prolog. Repre-
sentaremos um espao de estados pela relao
s(X, Y)
que verdadeira se h um movimento vlido no espao de estados de um nodo X a um nodo Y. Dize-
mos que o nodo Y um sucessor de X. Se h custos associados aos movimentos, ento adicionaremos
um terceiro argumento, representando o custo do movimento:
s(X, Y, Custo)
Essa relao pode ser representada explicitamente no programa por meio de um conjunto de fatos,
entretanto, para espaos de estado de maior complexidade, isso se torna impraticvel. Assim a relao
s/3 usualmente definida de maneira implcita, pelo estabelecimento de regras para computar os no-
dos sucessores de um determinado nodo.
Outra questo de importncia geral como representar as situaes do problema, isto , os nodos do
espao de estados. A representao deve ser compacta, mas por outro lado deve permitir uma execu-
o eficiente das operaes requeridas, particularmente a relao de sucesso, s/3.
Vamos considerar, por exemplo, o problema de organizao de blocos apresentado na Figura 14.1.
Estudaremos um caso mais geral, em que existe um nmero qualquer de blocos organizados em uma
ou mais pilhas. O nmero de pilhas ser limitado a um determinado mximo para tornar o problema
mais interessante. Isso pode corresponder tambm a uma restrio realstica, uma vez que a um rob
que manipule blocos somente pode ser oferecido um espao de trabalho limitado, sobre uma mesa.
143
Uma situao do problema pode ser representada por uma lista de pilhas. Cada pilha, por sua vez, ser
representada por uma lista de blocos, ordenada de forma que o bloco no topo da pilha a cabea da
lista. pilhas vazias sero representadas por listas vazias. A situao inicial do problema apresentado
na Figura 13.1 pode ser representada por:
[[c, a, b], [], []]
Uma situao objetivo qualquer arranjo com uma pilha ordenada de todos os blocos. H trs situa-
es objetivo possveis:
[[a, b, c], [], []]
[[], [a, b, c], []]
[[], [], [a, b, c]]
A relao s/3 pode ser programada de acordo com a seguinte regra: Uma situao s2 sucessora de
alguma situao s1, se h duas pilhas, P1 e P2 em s1 e bloco no topo de P1 pode ser movido para P2,
configurando a nova situao s2. Como todas as situaes so representadas por listas de pilhas, isso
pode ser escrito em Prolog da seguinte maneira:
s(Pilhas, [P1, [T1 | P2] | OutrasPilhas]) :-
remove([T1 | P1], Pilhas, Pilhas1),
remove(P2, Pilhas1, OutrasPilhas).
remove(X, [X | L], L).
remove(X, [Y | L], [Y | L1]) :-
remove(X, L, L1).
A condio objetivo para o problema dado :
objetivo(Situao) :-
membro([a, b, c], Situao).
Os algoritmos de pesquisa em espaos de estados sero solucionados por meio da relao:
resolve(Incio, Soluo)
onde Incio o nodo inicial do espao de estados e Soluo um caminho entre Incio e qualquer
nodo objetivo. Para o problema da organizao de blocos proposto, a consulta correspondente seria:
?-resolve([[c, a, b], [], []], Soluo).
Como resultado de uma pesquisa bem sucedida, a varivel Soluo ser instanciada para uma lista de
arranjos de blocos representando um "plano" para transformar o estado inicial em um estado onde os
trs blocos estejam em uma pilha organizada segundo a lista [a, b, c].
14.2 PESQUISA EM PROFUNDIDADE
Dada uma formulao do espao de estados de um problema, h diversas abordagens para encontrar o
caminho da soluo. Duas estratgias bsicas so: a pesquisa em profundidade (depth-first search) e a
pesquisa em amplitude (breadth-first search). na presente seo ser estudada a pesquisa em profundi-
dade, que pode ser formulada a partir de uma idia bastante simples:
Para encontrar uma linha de soluo, Sol, a partir de um determinado nodo, N, at algum nodo
objetivo:
Se N um nodo objetivo, ento Sol = [N], seno
Se h um nodo sucessor de N, N1, tal que existe um caminho, Sol1, de N1 at algum nodo
objetivo, ento Sol = [N | Sol1].
Pode-se representar essa formulao em Prolog por meio da seguinte relao resolve/2:
resolve(N, [N]) :-
objetivo(N).
resolve(N, [N | Sol1]) :-
s(N, N1), resolve(N1, Sol1).
144
Esse programa , na verdade, uma implementao da estratgia de pesquisa em profundidade. O m-
todo denominado "em profundidade" devido ordem em que as alternativas so exploradas no espa-
o de estados. Sempre que o algoritmo de pesquisa em profundidade tem oportunidade de continuar
sua pesquisa escolhendo entre diversos nodos alternativos, a deciso conduz ao n que se encontra em
maior profundidade, isto , ao mais distante possvel do nodo inicial. A Figura 14.4 ilustra a ordem na
qual os nodos so visitados, que corresponde ordem seguida pelo Prolog na soluo da consulta:
?-resolve(a, Sol).
A figura 14.4 representa um espao de estados onde "a" o nodo inicial e "f" e "g" so nodos objeti-
vos. A ordem na qual a pesquisa realizada dada pelo nmero entre parnteses esquerda de cada
nodo. A pesquisa em profundidade a mais adequada ao estilo recursivo da linguagem Prolog, uma
vez que esta, na execuo de seus objetivos, explora as alternativas segundo esse mesmo princpio.
Essa tcnica simples, fcil de programar, e funciona bem na maioria dos casos. Entretanto, h vrias
situaes em que o procedimento resolve/2, que adota o mtodo de pesquisa em profundidade , pode
se mostrar ineficiente. Se isso vai acontecer ou no, depende do espao de estados. Para complicar o
procedimento resolve/2, suficiente uma leve modificao no problema apresentado na Figura 14.4:
adicionar um arco do nodo h ao nodo d, originando um ciclo, como mostrado na Figura 14.5. Nesse
caso a pesquisa em profundidade ir ocorrer da seguinte maneira: inicia em a e desce at h, seguindo o
ramo mais esquerda no grafo. Neste ponto, ao contrrio do que ocorre na Figura 14.4, h tem um
sucessor, que d. Por sua vez, d tem h como sucessor, resultando em um ciclo infinito:
a, b, d, h, d, h, d, h, ...
a
b c
d e f g
i j k l h
(1)
(2)
(3) (5)
(4) (6) (7)
(8)
(9) (10)
(11) (12)
Figura 14.4: Pesquisa em Profundidade
a
b c
d e f g
i j k l h
Figura 14.5: Um espao de estados originando um caminho cclico
Um aperfeioamento bvio, portanto, em nosso programa de pesquisa em profundidade acrescentar
um mecanismo detector de ciclos. Assim, qualquer nodo que j houver sido visitado no deve ser
considerado novamente. Tal idia pode ser formulada por meio da relao:
145
profundidade(Caminho, Nodo, Soluo)
Na relao profundidade/3 , Nodo o estado a partir do qual o nodo objetivo deve ser encontrado.
Caminho um caminho (uma lista de nodos) entre o nodo inicial e Nodo, enquanto que Soluo
uma extenso de Caminho, passando por Nodo, at atingir um nodo objetivo. Essas idia so apre-
sentadas na Figura 14.6.
N
Nodo
inicial
Caminho
Nodo
objetivo
Soluo
Figura 14.6: A relao profundidade(Caminho, N, Soluo)
Para garantir uma programao simplificada, os caminhos sero representados em nossos programas
como listas em ordem inversa, isto , iniciando em um nodo objetivo (ou corrente, durante a execu-
o) e terminando no nodo inicial. O argumento "Caminho" pode ser utilizado para dois propsitos:
(1) Garantir que o algoritmo no ir considerar os sucessores de Nodo que j foram visitados (de-
teco de ciclos), e
(2) Construir um caminho, Soluo, que soluciona o problema.
Na Figura 14.7 apresentamos um programa que executa a pesquisa em profundidade em grafos com a
deteco de ciclos, conforme foi anteriormente comentado. Vamos considerar agora uma variao
desse programa. Dois argumentos que ali aparecem, N e Caminho, podem ser combinados em uma
lista [N | Caminho], assim, ao invs de se ter um "nodo candidato", N, para ser adicionado a um cami-
nho que conduza ao objetivo desejado, temos um "caminho candidato", C = [N | Caminho], para ser
ampliado at alcanar o objetivo. A programao do predicado correspondente, profundidade1(C,
Soluo) deixada como um exerccio.
resolve(N, Soluo) :-
profundidade([], N, Soluo).
profundidade(Caminho, N, [N | Caminho]) :-
objetivo(N).
profundidade(Caminho, N, Soluo) :-
s(N, N1),
not membro(N1, Caminho),
profundidade([N | Caminho], N, Soluo).
Figura 14.7: Pesquisa em profundidade com deteco de ciclos
Com o mecanismo de deteco de ciclos, o procedimento de pesquisa em profundidade vai encontrar
o caminho apropriado para atingir uma soluo em espaos de estados tais como o apresentado na
Figura 14.5. H entretanto espaos de estados para os quais esse procedimento no funcionar ade-
quadamente. Muitos espaos de estado so infinitos. Em tais espaos o algoritmo de pesquisa em pro-
fundidade pode se desviar do caminho correto para atingir um determinado objetivo, explorando inde-
finidamente uma ramificao infinita que jamais se aproximar do objetivo formulado. Para evitar a
pesquisa em profundidade em ramificaes infinitas (no- cclicas, neste caso) do espao de estados,
adicionaremos mais um refinamento em nosso procedimento bsico de pesquisa em profundidade:
limitamos a profundidade mxima de pesquisa, obtendo uma nova relao, profundidade2/3, repre-
sentada por:
profundidade2(Nodo, Soluo, ProfMxima)
146
onde a pesquisa no permitida alm de ProfMxima. Essa restrio pode ser programada decremen-
tando o valor estabelecido para ProfMxima a cada chamada recursiva, no permitindo que esse limite
se torne negativo. O programa resultante mostrado na Figura 14.8.
profundidade2(Nodo, [Nodo], _) :-
objetivo(Nodo).
profundidade2(Nodo, [Nodo | Sol], ProfMxima) :-
ProfMxima > 0,
s(Nodo, Nodo1),
Max1 is ProfMxima -1,
profundidade2(Nodo1, Sol, Max1).
Figura 14.8: Um programa para pesquisa em profundidade limitada
14.3 PESQUISA EM AMPLITUDE
Em contraste com a pesquisa em profundidade, a pesquisa em amplitude escolhe visitar primeiro os
nodos que esto mais prximos do nodo inicial. Isso resulta em um processo de busca que tende a se
desenvolver mais em amplitude do que em profundidade, como pode ser visto na Figura 14.9. O espa-
o de estados ali apresentado basicamente o mesmo da Figura 14.4, entretanto, a ordem em que os
nodos sero visitados, dada pelo nmero entre parnteses esquerda de cada nodo, agora diferente.
a
b c
d e f g
i j k l h
(1)
(2)
(4) (5)
(8) (9) (10)
(3)
(6) (7)
(11) (12)
Figura 14.9: Pesquisa em amplitude
A estratgia de pesquisa em amplitude no to fcil de programar quanto a de pesquisa em profun-
didade. A razo dessa dificuldade que temos de manter um conjunto de nodos candidatos alternati-
vos, e no apenas um nodo como na pesquisa em profundidade. Entretanto, mesmo esse conjunto de
nodos no suficiente se desejarmos extrair um caminho-soluo por meio desse processo. Assim, ao
invs de manter um conjunto de nodos candidatos, iremos manter um conjunto de caminhos candida-
tos. Isso representado pela relao:
amplitude(Caminhos, Soluo)
que verdadeira quando algum caminho pertencente ao conjunto de candidatos Caminhos pode ser
estendido at algum nodo objetivo. O argumento soluo representa tal caminho estendido.
14.3.1 REPRESENTAO DO CONJUNTO DE CAMINHOS CANDIDATOS
Vamos adotar inicialmente a seguinte representao para o conjunto de caminhos candidatos: O con-
junto ser representado como uma lista de caminhos, onde cada caminho uma lista de nodos em
ordem inversa, isto , a cabea da lista ser o nodo mais recentemente visitado e o ltimo elemento da
lista ser o nodo inicial da pesquisa. O conjunto inicia como um conjunto unitrio de caminhos candi-
datos:
[ [NodoInicial] ]
Um esquema para definir o processo de pesquisa em amplitude pode ser formulado da seguinte manei-
147
ra:
Para executar a pesquisa em amplitude, dado um conjunto de caminhos candidatos:
Se o primeiro caminho contm um nodo objetivo como cabea da lista que o representa, en-
to ele uma soluo para o problema, seno
Remover o primeiro caminho da lista de caminhos candidatos e gerar o conjunto de todas as
possveis extenses de um s nodo a esse caminho, adicionando o conjunto das extenses
geradas ao final da lista de caminhos candidatos. Aps, voltar a executar a pesquisa em am-
plitude sobre esse conjunto atualizado.
Por exemplo, para o espao de estados apresentado na Figura 14.9, onde f e j so nodos objetivo, o
processo se desenvolve da seguinte maneira:
(1) O conjunto de caminhos candidatos inicialmente contm apenas o nodo raiz:
[ [a] ]
(2) Determinar o conjunto de extenses de um s nodo de [a]:
[ [b,a], [c,a] ]
(3) Remover o primeiro caminho candidato, [b, a] do conjunto e determinar suas extenses de um
s nodo:
[ [d,b,a], [e,b,a] ]
Acrescentar essa lista de extenses ao final do conjunto de caminhos candidatos:
[ [c,a], [d,b,a], [e,b,a] ]
(4) Remover [c, a] e acrescentar suas extenses ao final do conjunto de caminhos candidatos pro-
duzindo:
[ [d,b,a], [e,b,a], [f,c,a], [g,c,a] ]
(5) Remover [d, b, a] e acrescentar sua nica extenso ao final do conjunto de caminhos candida-
tos:
[ [e,b,a], [f,c,a], [g,c,a], [h,d,b,a] ]
(6) Executar a mesma operao para [e, b, a], obtendo:
[ [f,c,a], [g,c,a], [h,d,b,a], [i,e,b,a], [j,e,b,a] ]
Aqui o processo de busca encontra |, c, a|, que contm como cabea o nodo objetio . Lntao
esse caminho apresentado como soluao.
Um programa que executa esse processo apresentado na Figura 14.10. Ali, todas as extenses aos
conjuntos candidatos so geradas atravs do predicado pr-definido bagof/3. Um teste para prevenir a
gerao de ciclos tambm includo. Note que no caso em que nenhuma extenso possvel, o predi-
cado bagof/3 falha, portanto fornecida uma chamada alternativa ao procedimento amplitude/2. Os
predicados membro/2 e conc/3 so respectivamente as relaes de ocorrncia de um item em uma lista
e a concatenao de listas, ambas j estudadas.
O problema desse programa a ineficincia da operao conc/3. Isso entretanto pode ser reparado se
representarmos listas por meio de pares-diferena conforme foi apresentado no captulo 12. O con-
junto de caminhos candidatos seria ento representado como um par de listas: Caminhos e Z, e escrito
como
Caminhos-Z
Introduzindo essa representao no programa da Figura 14.10, este pode ser sistematicamente trans-
formado no programa apresentado na Figura 14.11. A transformao (simples) deixada ao leitor a
ttulo de exerccio.
resolve(Incio, Soluo) :-
148
amplitude([ [Incio] ], Soluo).
amplitude([ [N | Caminho] | _ ], [N | Caminho]) :-
objetivo(N).
amplitude([ [N | Caminho] | Caminhos ], Soluo) :-
bagof([M, N | Caminho],
(s(M, N), not membro(M, [N | Caminho])),
NovosCaminhos),
conc(Caminhos, NovosCaminhos, Caminhos1), !,
amplitude(Caminhos1, Soluo);
amplitude(Caminhos, Soluo).
Figura 14.10: Uma implementao da pesquisa em amplitude
resolve(Incio, Soluo) :-
amplitude1([ [Incio] | Z ] - Z, Soluo).
amplitude1([ [N | Caminho] | _ ] - _, [N | Caminho]) :-
objetivo(N).
amplitude1([ [N | Caminho] | Caminhos ] - Z, Soluo) :-
bagof([M, N | Caminho],
(s(M, N), not membro(M, [N | Caminho])),
NovosCaminhos),
conc(NovosCaminhos, ZZ, Z), !,
amplitude1(Caminhos1 - ZZ, Soluo);
Caminhos \== Z,
amplitude1(Caminhos - Z, Soluo).
Figura 14.11: Uma implementao mais eficiente do programa da Figura 14.10
14.3.2 REPRESENTAO EM RVORE DO CONJUNTO DE CAMINHOS CANDIDATOS
Vamos considerar agora outra modificao no programa de pesquisa em amplitude. At ento o con-
junto de caminhos candidatos vinha sendo representado como uma lista de caminhos. Isso gera um
consumo exagerado de memria, uma vez que a parte inicial a mesma para diversos caminhos, sen-
do armazenada de forma redundante. A maneira mais eficiente de representar os caminhos candidatos
em forma de rvore, onde a parte comum a diversos caminhos armazenada sem redundncia, nos
ramos superiores da rvore. Adotaremos a seguinte representao de rvore. necessrio considerar
dois casos:
(1) A rvore consiste em um nico nodo N. Ento ela ser representada pelo termo f(N), onde o
functor f indica que N uma folha da rvore;
(2) A rvore consiste em um nodo raiz, N, e um conjunto de sub-rvores. Tal rvore dada pelo
termo t(N, Subs), onde Subs = [S1, S2, ...] uma lista de sub-rvores.
Por exemplo, vamos considerar uma situao onde os trs primeiros nveis da rvore apresentada na
Figura 14.9 foram gerados. O conjunto de caminhos candidatos nesse momento o seguinte:
[ [d, b, a], [e, b, a], [f, c, a], [g, c, a] ]
Na representao em rvore, esse mesmo conjunto de caminhos candidatos representado pelo termo:
t(a, [t(b, [f(d), f(e)]), t(c, [f(f), f(g)])])
Essa representao pode parecer complexa e ainda mais consumidora de memria do que a represen-
tao em listas, entretanto isso apenas a aparncia superficial, devido representao compacta que
o Prolog utiliza para listas. Na representao do conjunto candidato por meio de listas, o efeito da
pesquisa em profundidade era atingido pela movimentao dos caminhos expandidos para o fim do
conjunto candidato. No possvel usar o mesmo truque na representao em rvore, portanto nosso
novo programa ser algo mais complicado. A relao chave aqui ser:
expande(Caminho, Arv, Arv1, Sol, Soluo)
A Figura 14.12 ilustra a relao entre os argumentos da relao expande/5. Sempre que esta for ativa-
149
da, as variveis Caminho e Arv j devem estar instanciadas. Arv uma sub-rvore do espao de esta-
dos e representa o conjunto de caminhos candidatos a um objetivo nessa sub-rvore. Caminho o
caminho entre o nodo inicial e a raiz de Arv. A idia geral da relao expande/5 produzir Arv1 como
uma extenso de um nvel de Arv. Se, entretanto, durante a expanso de Arv, um nodo objetivo for
encontrado, expande/5 produzir o correspondente caminho soluo. Assim a relao expande/5 ir
produzir dois tipos de resultados. O tipo de resultado produzido ser indicado pelo valor da varivel
Sol, como se segue:
(1) Sol = sim,
Soluo = um caminho para solucionar o problema, e
Arv1 = no instanciada.
Resultados desse tipo somente sero produzidos quando houver um nodo objetivo em Arv (uma
"folha-objetivo").
(2) Sol = no,
Soluo = no instanciada,
Arv1 = Arv expandida de um nvel.
Aqui Arv1 no contm nenhum desvio bloqueado, (desvios que no podem ser expandidos por-
que no possuem sucessores)
a Caminho
Arv Arv1
g
Soluo
Figura 14.12: A relao expande(Caminho,Arv,Arv1,Sol,Soluo)
A Figura 14.13 apresenta um programa completo, baseado nas idias discutidas acima, empregando
representao em rvore para o conjunto de caminhos candidatos. Um procedimento auxiliar
expTodos/6, similar ao expande/5, que realiza a expanso de um nvel sobre um conjunto de rvores e
armazena todas as rvores expandidas resultantes, removendo todas as rvores bloqueadas. Alm dis-
so esse procedimento produz, atravs de backtracking, todas as solues encontradas nessa lista de
rvores.
150
resolve(Incio, Soluo) :-
ampl(f(Incio), Soluo).
ampl(Arv, Soluo) :-
expande([], Arv, Arv1, Sol, Soluo),
(Sol=sim; Sol=no, ampl(Arv1, Soluo)).
expande(P, f(N), _, sim, [N | P]) :-
objetivo(N).
expande(P, f(N), t(N, Subs), no, _) :-
bagof(f(N), (s(N, M), not membro(M, P)), Subs).
expande(P, t(N, Subs), t(N, Subs1), Sol, Soluo) :-
expTodos([N | P], Subs, [], Subs1, Sol, Soluo).
expTodos(_, [], [T | Ts], [T | Ts], no, _).
expTodos(P, [T | Ts], Ts1, Subs1, Sol, Soluo) :-
expande(P, T, T1, Sol1, Soluo),
( Sol1=sim, Sol=Sim;
Sol1=no, !, expTodos(P,Ts,[T1 | Ts1], Subs, Sol, Soluo));
expTodos(P, Ts, Ts1, Subs1, Sol, Soluo).
Figura 14.13: Uma implementao do mtodo de pesquisa em profundidade usando representao em
rvore para o conjunto de caminhos candidatos
14.4 PESQUISA EM GRAFOS, OTIMIZAO E COMPLEXIDADE
Neste ponto conveniente tecer alguns comentrios sobre as tcnicas estudadas at agora para a pes-
quisa em espaos de estados: pesquisa em grafos, otimizao das solues produzidas e complexidade
de pesquisa.
Os exemplos apresentados neste captulo podem produzir a falsa impresso de que os programas de
pesquisa em amplitude somente funcionam para espaos de estado que podem ser representados por
meio de rvores e que no so adequados para grafos em geral. O fato de se haver adotado uma repre-
sentao em rvore no significa que o espao de estados tenha obrigatoriamente de ser uma rvore.
Na verdade, quando um espao de estados na forma de um grafo pesquisado, ele se desdobra em
uma rvore, de forma que os mesmos caminhos percorridos podem ser representados em ambas as
estruturas. Isso ilustrado pela figura 14.14.
a
b c
d e
a
b c
d e c e
e
(1) (2)
Figura 14.14: Desdobrando um grafo em uma rvore.
Em (1) representa-se um espao de estados na forma de grafo. Se "a" arbitrado o nodo inicial, ento
o grafo pode ser desdobrado na forma da rvore mostrada em (2), que contm todos os caminhos no-
cclicos possveis desenvolvidos a partir de "a". A tcnica de pesquisa em amplitude gera caminhos de
soluo, um aps outro, ordenados de acordo com o seu tamanho: os caminhos mais curtos aparecem
primeiro. Isso importante se a otimizao (no que toca ao comprimento do caminho deva ser consi-
151
derada. A tcnica de pesquisa em amplitude garantidamente produz o caminho mais curto primeiro, o
que no ocorre com a tcnica de pesquisa em profundidade. O programa dado na Figura 14.13, entre-
tanto, no leva em conta os custos associados aos arcos do espao de estados. Se o custo mnimo de
um caminho de soluo o critrio para otimizao (e no o seu tamanho), ento a tcnica de pesqui-
sa em amplitude no suficiente.
Outro problema tpico associado com a pesquisa de espaos de estado o da complexidade combina-
tria. Para os domnios de problemas no-triviais, o nmero de alternativas a ser explorado to
grande que o problema da complexidade freqentemente se torna crtico. fcil entender porque isso
acontece: se cada nodo no espao de estados tem n sucessores, ento o nmero de caminhos de com-
primento c a partir do nodo inicial n
c
(assumindo a inexistncia de ciclos). Assim, o conjunto de
caminhos candidatos cresce exponencialmente com o seu tamanho, o que conduz ao que se denomina
exploso combinatria. As tcnicas de pesquisa em profundidade e em amplitude no possuem ne-
nhum recurso contra essa complexidade, uma vez que todos os caminhos candidatos so tratados de
forma no-seletiva.
Um procedimento mais sofisticado para a pesquisa em espaos de estados complexos deveria empre-
gar informaes especificamente relacionadas ao problema de decidir a maneira mais promissora de
agir em cada ponto da pesquisa. Isso teria o efeito de projetar o processo de pesquisa diretamente para
o objetivo procurado, evitando os caminhos improdutivos. Informao associada ao problema espec-
fico que pode ento ser empregada para dirigir a pesquisa denominada heurstica. Os algoritmos que
utilizam heursticas so denominados heuristicamente guiados e executam um tipo de pesquisa cha-
mada pesquisa heurstica, que ser introduzida no prximo captulo.
RESUMO
Um espao de estados um formalismo para a representao de problemas de planejamento.
Um espao de estados representado por meio de um grafo direcionado cujos nodos corres-
pondem a situaes do problema e os arcos a movimentos vlidos que transformam uma situa-
o em outra. Um problema particular definido por um nodo inicial e um nodo objetivo. Uma
soluo do problema corresponde ento a um caminho no grafo. Assim, a soluo do problema
reduzida procura por um caminho em um grafo.
Problemas de otimizao podem ser modelados pela associao de custos aos arcos de um es-
pao de estados.
Duas estratgias basicas que sistematicamente exploram um espao de estados sao: a pes-
quisa em proundidade ,depth-irst search, e a pesquisa em amplitude ,breadth-irst se-
arch,.
A pesquisa em profundidade mais fcil de programar, mas suscetvel presena de ciclos
entre os nodos, conduzindo a ramificaes infinitas da arvore de pesquisa.
A implementao da estratgia de pesquisa em amplitude mais complexa, uma vez que requer
a manuteno de um conjunto de caminhos candidatos. Isso pode ser mais facilmente represen-
tado por meio de uma lista de listas, entretanto, o mtodo mais eficiente emprega representao
em rvore.
No caso de grandes espaos de estados h o perigo da exploso combinatria. Tanto a pesquisa
em profundidade quanto a pesquisa em amplitude so ferramentas pobres no combate a tal difi-
culdade, onde a aplicao de tcnicas de pesquisa heurstica se faz necessria.
EXERCCIOS
14.1 Escreva um procedimento denominado
152
profundidade1(CaminhoCandidato, Soluo)
com deteco de ciclos, para encontrar um caminho, Soluo, como uma extenso de Caminho-
Candidato. Represente ambos os caminhos como listas de nodos em ordem inversa, de forma que
o nodo objetivo a cabea da lista Soluo.
14.2 Escreva um procedimento para pesquisa em profundidade combinando os mecanismos de detec-
o de ciclos e o de limitao da profundidade pesquisada.
14.3 Escreva um procedimento denominado
apresenta(Situao)
para representar um estado do mundo dos blocos. Situao deve ser representada por uma lista de
pilhas e cada pilha como uma lista de blocos. Por exemplo, o objetivo
mostra( [ [a], [e, d], [c, b] ]).
ir ocasionar a apresentao de
e c
a d b
=======================
14.4 Como se pode usar os procedimento de pesquisa em amplitude estudados para permitir a pesqui-
sa a partir de um conjunto de nodos iniciais, ao invs de um nico?
14.5 Como se pode usar os procedimentos de pesquisa em profundidade e amplitude estudados para
executar a pesquisa em direo inversa, isto , a partir dos nodos objetivos retroagir at atingir
um nodo inicial. (Dica: redefina a relao s/2). Em que situaes a pesquisa retroativa seria van-
tajosa em relao pesquisa progressiva?
14.6 Considere que h custos associados aos arcos de um espao de estados. Escreva um programa
(com deteco de ciclos que efetue a progresso em profundidade ou em amplitude, buscando
minimizar o custo total da pesquisa.
153
15. PESQUISA HEURSTICA
A pesquisa em grafos para a soluo de problemas pode conduzir ao problema da exploso combina-
tria, devido proliferao de alternativas. A pesquisa heurstica representa uma maneira de combater
tal situao. Uma forma de utilizar informao heurstica sobre um problema computar estimativas
heursticas numricas para os nodos no espao de estados. Tal estimativa em um nodo indica o quanto
promissor ele se mostra para atingir um nodo objetivo. A idia continuar a pesquisa sempre a partir
do nodo mais promissor dentre os que compem o conjunto de candidatos. O programa de pesquisa
heurstica (best-first search), apresentado no presente captulo, baseia-se nesse princpio.
15.1 BEST-FIRST SEARCH
Um programa de pesquisa heurstica pode ser derivado como um refinamento do programa de pesqui-
sa em amplitude apresentado no captulo anterior. A pesquisa heurstica tambm inicia no primeiro
nodo e mantm um conjunto de caminhos candidatos. A pesquisa em amplitude sempre escolhe para
expanso os caminhos mais curtos. A pesquisa heurstica refina este princpio pela computao de
uma estimativa heurstica para cada candidato e escolhe para expanso o melhor candidato de acordo
com essa estimativa. A partir de agora vamos assumir que h uma funo de custo definida sobre os
arcos do espao de estados. Assim, c(n, n') o custo de movimentao de um nodo n para um nodo
sucessor n' no espao de estados.
Seja a estimativa heurstica traduzida por uma funo f tal que para cada nodo n do espao de estados,
f(n) estima a "dificuldade" de n. Ento, o nodo candidato mais promissor ser aquele que minimizar o
valor de f. A funo f(n) projetada de forma que, para estimar o custo de um caminho que conduza
at a soluo, percorrendo o caminho entre um nodo s, inicial, e um nodo objetivo, final, deva neces-
sariamente passar por um determinado nodo n. Vamos supor que existe tal caminho e que um nodo
objetivo que minimize o seu custo seja t. Ento a funo f(n) pode ser construda como a soma de dois
termos:
f(n) = g(n) + h(n)
conforme ilustrado na figura 15.1.
s
n
t
g(n)
h(n)
Figura 15.1: Construo de uma estimativa heurstica f(n) do custo
do caminho mais barato de s a t via n: f(n) = g(n) + h(n).
A funo g(n) representa a estimativa do custo de um caminho timo de s a n. h(n) representa a esti-
mativa do custo de um caminho timo de n a t.
Quando um nodo n encontrado pelo processo de pesquisa, temos a seguinte situao: Um caminho
de s a n j foi encontrado e o seu custo pode ser computado como a soma dos custos dos arcos nesse
caminho. Esse caminho no necessariamente um caminho timo de s a n (pode haver um caminho
154
melhor de s a n ainda no encontrado pela pesquisa) mas o seu custo pode servir *como um valor
estimativo g(n) do custo mnimo de s a n. O outro termo, h(n) mais problemtico porque o espao
entre n e t ainda no foi explorado nesse ponto. Assim o valor de h(n) tipicamente uma perspectiva
heurstica real, baseada no conhecimento geral do algoritmo acerca do domnio do problema particu-
lar que esta sendo solucionado. Como h(n) depende muito fortemente do domnio do problema, no
h um mtodo universal para a sua construo. Exemplos concretos de como essa previso heurstica
pode ser estabelecida sero apresentados mais adiante. De momento vamos assumir que a funo h
dada e nos concentrar nos outros detalhes do programa de pesquisa heurstica.
Pode-se imaginar que a pesquisa heurstica funcione da seguinte maneira: o processo de pesquisa
consiste em diversos subprocessos competindo entre si, cada um dos quais explorando suas prprias
alternativas, isto , executando a pesquisa sobre os ramos de suas prprias sub-rvores. As sub-
rvores, por sua vez, so constitudas de outras sub-rvores que so exploradas por subprocessos de
subprocessos e assim por diante.
Entre todos esses processos competitivos, somente um est ativo em cada instante: o que lida com a
alternativa mais promissora naquele momento, isto a alternativa cujo valor para a funo f o mais
baixo. Os processos restantes permanecem congelados at que o valor de f do processo em curso seja
modificado de maneira que uma outra alternativa se revele mais promissora. Ento a atividade dada
a essa alternativa. Pode-se imaginar esse mecanismo de ativao e desativao da seguinte maneira:
ao processo trabalhando sobre a alternativa mais promissora dado um crdito e o processo permane-
ce ativo at que esse crdito tenha se esgotado. Durante o perodo em que est ativo, o processo conti-
nua a expanso da sua sub-rvore, informando uma soluo se algum nodo objetivo for encontrado. O
crdito para cada passo de execuo definido pela estimativa heurstica da alternativa competidora
mais prxima. Esse comportamento exemplificado na Figura 15.2, que se divide em duas partes
principais. Em (a) representado uma mapa rodovirio (sem qualquer pretenso de representao em
escala) onde as cidades so os nodos e os arcos representam estradas, rotuladas com as respectivas
distncias em alguma unidade qualquer. O objetivo atingir a cidade t partindo de s, no menor trajeto
rodovirio possvel. os valores entre colchetes representam a distncia em linha reta entre cada cidade
e a cidade objetivo t. Esses valores sero utilizados para computar a funo heurstica que prev a
distncia que resta a ser percorrida a partir de cada nodo, h(n). Em (b) representada a ordem na qual
o mapa explorado por meio da pesquisa heurstica. A funo estimativa heurstica considera a dis-
tncia at ento percorrida e a que resta percorrer estimada em funo da distncia em linha reta at
t, dada em (a) pelos valores entre colchetes. os valores entre parnteses em (b) indicam a troca de
atividade entre os caminhos alternativos, representando a ordem em que os nodos so expandidos e
no a ordem em que so gerados. Na estimativa do custo da distncia que resta a percorrer a partir de
uma cidade X at o objetivo t, usamos a distncia em linha reta denotada por dist(X, t), de modo que:
f(X) = g(X) + h(X) = g(X) + dist(X, t)
No exemplo dado podemos imaginar a pesquisa heurstica como constituda por dois processos, cada
um deles explorando uma das duas rotas alternativas: o processo 1 a rota a partir de a e o processo 2 a
rota a partir de e. Nos estgios iniciais, o processo 1 mais ativo porque os valores de f ao longo des-
se caminho so os mais baixos. No momento em que o processo 1 est em c e o processo 2 ainda no
saiu de e, a situao muda:
f(c) = g(c) + h(c) = 6 + 4 = 10
f(e) = g(e) + h(e) = 2 + 7 = 9
ento, como f(e) < f(c), o processo 2 ativado, deslocando a rota para f enquanto o processo 1 espera.
Aqui, entretanto, a situao mais uma vez se inverte, pois:
f(f) = 7 + 4 = 11
f(c) = 6 + 4 =10
f(c) < f(f)
155
s e
a
b
c
d t
f
g
2 5
2
2
2
3
3
2
2
(a)
[7]
[5]
[4]
[4]
[3]
(b)
[4]
[2]
s
a e
b
c
d
f
g
t
f(a)=2+5=7
4+4=8
6+4=10
9+3=12
f(e)=2+7=9
7+4 =11
9+2=11
11+0=11
(1)
(2)
(4)
(3)
(5)
(6)
Figura 15.2: Encontrando a rota mais curta entre s e t em um mapa
Portanto o processo 2 pra e o processo 1 novamente ativado. mas em seguida, no nodo d, temos
f(d) = 12 > 11. A ativao passa mais uma vez ao processo 2 que, a partir da, acaba por atingir o ob-
jetivo t. Vamos programar a pesquisa heurstica como um refinamento do programa de pesquisa em
amplitude estudado no captulo anterior. O conjunto de caminhos candidatos ser mais uma vez repre-
sentado por uma rvore dada por meio de dois tipos de termos:
(1) n(N, F/G) representa um nico nodo (uma folha). N um nodo no espao de estados. G
g(N), o custo do caminho percorrido desde o nodo inicial at N, e F f(N)=G+h(N), e
(2) t(N, F/G, Subs) representa uma rvore com sub-rvores no-vazias. N a raiz da rvore, Subs
uma lista de sub-rvores, G g(N) e F o valor atualizado da funo f, isto , o valor de f
para o sucessor mais promissor de N. A lista Subs ordenada de acordo com valores crescentes
de f para as sub-rvores que a compem.
A atualizao dos valores de f necessria para permitir ao programa reconhecer a sub-rvore mais
promissora a cada nvel da rvore de pesquisa, isto , a sub-rvore que contm o nodo mais promissor.
Essa modificao dos valores de f conduz , na verdade, a uma generalizao da definio da funo f.
Tal generalizao amplia o domnio de definio de f, de nodos para rvores. Para um nico nodo da
rvore (uma folha), n, temos a definio original:
f(n)= g(n) + h(n)
Para uma rvore T cuja raiz n e cujos sucessores de n so m1, m2, m3, etc, temos:
f(T) = min f(m
i
)
Um programa para executar pesquisa heurstica segundo as linhas apresentadas dado na Figura 15.3
156
heurist(Incio, Soluo) :-
maior(M), % M > qualquer valor de f
expande([], n(Incio, O/O), M, _, sim, Soluo).
expande(P, n(N, _), _, _, sim, [N | P]) :-
objetivo(N).
expande(P, n(N, F/G), Limite, , Arv1, Sol, Soluo) :-
F =< Limite,
(bagof(M/C, (s(N,M,C), not membro(M,P)), Suc), !,
sucLista(G, Suc, Ts), bestf(Ts, F1),
expande(P,t(N,F1/G,Ts),Limite,Arv1,Sol,Soluo);
Sol = nunca).
expande(P,t(N,F/G,[T|Ts]),Limite, ,Arv1,Sol,Soluo) :-
F =< Limite,
bestf(Ts, BF),
min(Limite, BF, Limite1),
expande([N|P], T, Limite1, T1, Sol, Soluo),
continua(P, t(N, F/G, [T1|Ts]),
Limite, Arv1, Sol1, Sol, Soluo).
expande(_, t(_, _, []), _, _, nunca, _).
expande(_, Arv, Limite, Arv, no, _) :-
f(Arv, F), F > Limite.
continua(_,_,_,_,sim, sim, Soluo).
continua(P,t(N,F/G,[T1|Ts]),Lim,Arv1,Sol1,Sol,Soluo):-
(Sol1=no, insere(T1,Ts,NTs); Sol1=nunca, Ts=Ts),
bestf(NTs, F1),
expande(P,t(N,F1/G,NTs),Lim,Arv1,Sol,Soluo).
sucLista(_, [], []).
sucLista(G0, [N/C | NCs], Ts) :-
G is G0+C, h(N, H), F is G+H,
sucLista(G0, NCs, Ts1),
insere((n(N, F/G), Ts1, Ts).
insere(T, Ts, [T|Ts]) :-
f(T, F),
bestf(Ts, F1),
F =< F1, !.
insere(T, [T1|Ts], [T1|Ts1]) :-
insere(T, Ts, Ts1).
f(n(_, F/_), F).
f(t(_, F/_, _), F).
bestf([T|_], F) :-
f(T, F).
bestf([], M) :-
maior(M).
min(X, Y, X) :- X =< Y, !.
min(X, Y, Y).
Figura 15.3: Um programa de pesquisa heurstica.
Como no programa de pesquisa em amplitude apresentado no captulo anterior, o procedimento chave
aqui expande/6, agora com um argumento adicional:
expande(P, Arv, Limite, Arv1, Sol, Soluo)
e que corresponde expanso da sub-rvore corrente enquanto o seu valor de f for menor ou igual a
Limite. Os argumentos de expande/6 so:
P: Caminho entre o nodo inicial e Arv;
Arv: Sub-rvore de pesquisa corrente;
Limite: Limite do valor de f para a expanso de Arv;
Arv1: Arv expandida dentro do valor Limite. Consequentemente o valor de f para Arv1
maior do que Limite, a menos que um nodo objetivo tenha sido atingido;
Sol: Indicador que pode assumir os valores sim, no ou nunca;
157
Soluo: Um caminho-soluo a partir do nodo inicial, passando por Arv1 at um nodo objetivo
dentro do valor Limite.
Os parmetros P, Arv e Limite so os argumentos de entrada do procedimento expande/6, isto , eles
devem estar instanciados sempre que esse procedimento for chamado. O procedimento expande/6
produz trs tipos de resultados, o que indicado pelo valor do argumento Sol, da seguinte maneira:
(1) Sol = sim;
Soluo = Um caminho-soluo, encontrado pela expanso de Arv dentro do valor Limite;
Arv1 = No instanciada.
(2) Sol = no;
Soluo = No instanciada;
Arv1 = Arv expandida de forma que seu valor para f excede o valor de Limite.
(3) Sol = nunca;
Soluo = No instanciada;
Arv1 = No instanciada..
O ltimo caso indica que Arv uma alternativa "morta" qual no deve ser dada nenhuma chance de
expanso posterior. Esse caso surge quando o valor de f para Arv menor ou igual ao valor de Limite
mas a rvore no pode ser expandida porque nenhum nodo nela possui sucessor, ou ento tal sucessor
iria originar um ciclo.
Algumas das clusulas sobre expande/6 merecem uma explicao mais detalhada: As clusulas que
lidam com o caso mais complexo, quando Arv possui sub-rvores, isto :
Arv = t(N, F/G, [T | Ts])
Em tais casos, primeiro a sub-rvore mais promissora, T expandida. essa expanso no dado o
limite Limite, mas possivelmente algum valor mais baixo, dependendo dos valores de f para as outras
sub-rvores competidoras, Ts. Isso assegura que a sub-rvore em expanso em um determinado mo-
mento sempre a mais promissora. Aps o melhor caminho candidato ter sido expandido, um proce-
dimento auxiliar, continua/7 decide o que fazer a seguir. Isso depende do tipo de resultado produzido
pela ltima expanso. Se uma soluo foi encontrada, ento ela relatada ao usurio, seno o proces-
so continua.
A clusula que lida com o caso
Arv = n(N, F/G)
gera os nodos sucessores de N, juntamente com os custos dos arcos entre N e esses sucessores. O
procedimento sucLista/3 organiza uma lista de sub-rvores a partir desses nodos sucessores, tambm
computando seus valores para as funes f e g. A rvore resultante ento expandida enquanto o va-
lor de Limite permitir. Se, por outro lado, no h sucessores, ento o nodo abandonado para sempre,
pela instanciao de Sol = nunca. Outras relaes a considerar so:
s(N, M, C): M um nodo sucessor de N no espao de estados. C o custo do arco que liga N a
M.
h(N, H): H uma estimativa heurstica do custo do melhor caminho do nodo N a algum nodo
objetivo.
maior(M): M algum valor especificado pelo usurio, reconhecidamente maior do que qualquer
valor possvel para f
O programa apresentado na Figura 15.3 uma variao de um algoritmo heurstico, conhecido na
literatura como A
*
. Esse algoritmo sempre atraiu a ateno dos pesquisadores devido a suas caracte-
rsticas particulares. Um importante resultado extrado da anlise matemtica de A
* o seguinte:
Um algoritmo de pesquisa dito ser admissvel se sempre produz uma soluo tima (isto ,
158
um caminho de custo mnimo), se tal soluo existe. O programa da Figura 15.3, que produz
por backtracking todas as solues possveis, pode ser considerado admissvel se a primeira
soluo encontrada for uma soluo tima. Considerando que para cada nodo n no espao de
estados, h*(n) denota o custo do caminho timo de n at um nodo objetivo. Um teorema sobre
a admissibilidade de
A
* diz que: Um algoritmo
A
* que utiliza uma funo heurstica h tal que
para todos os nodos n de um espao de estados, h(n)
h
*(n), admissvel.
Esse resultado possui um grande valor prtico. Mesmo sem conhecer o valor exato de h* podemos
encontrar um limite inferior de h* e empreg-lo como se fosse h em
A
*. Isso garantia suficiente de
que
A
* ir produzir uma soluo tima. H um limite inferior trivial: h(n) = 0, para todo n no espao
de estados. Isso, na verdade, garante a admissibilidade. A desvantagem de se ter h = 0 que isso no
possui qualquer potencial heurstico e no oferece nenhuma orientao para a pesquisa.
A
* usando h
= 0 se comporta de maneira similar pesquisa em amplitude. Na verdade se reduz pesquisa em am-
plitude no caso em que a funo de custo dos arcos c(n, n') possui o valor 1 para todos os arcos (n, n')
do espao de estados. A falta de potencial heurstico resulta em elevada complexidade, assim deseja-
ramos ter valores para h que fossem limites inferiores de h* (para assegurar a admissibilidade), mas
que fossem to prximos quanto possvel de h* (para assegurar a eficincia). No caso ideal, se conhe-
cemos o valor de h*, usamos esse prprio valor. Um algoritmo
A
* usando h* encontra a soluo ti-
ma diretamente, sem a necessidade de backtracking.
15.2 UMA APLICAO DA PESQUISA HEURSTICA
Para aplicar o programa da Figura 15.3 a algum problema particular, temos que adicionar as relaes
especficas do problema em questo. Tais relaes, alm de definir o problema, tambm transmitem,
na forma de funes heursticas, a informao heurstica necessria sua resoluo. Os predicados
especficos do problema so (1) s(Nodo, Nodo1, Custo), que verdadeiro se existe um arco de custo
Custo entre Nodo e Nodo1 no espao de estados, (2) objetivo(Nodo), que verdadeiro se Nodo um
nodo objetivo no espao de estados, e (3) h(Nodo, H), onde H uma estimativa heurstica do custo do
caminho mais barato de Nodo at um nodo objetivo.
Como um exemplo iremos retomar o processo do jogo do oito, apresentado no captulo anterior. As
relaes especficas do jogo do oito so apresentadas na figura 15.5. Um nodo no espao de estados
corresponde, nesse caso, a alguma configurao das peas do jogo. No programa isto representado
por meio de uma lista contendo as posies correntes das peas. Cada posio representada por um
par de coordenadas X/Y. A ordem das posies na lista a seguinte:
(1) Posio da casa vazia,
(2) Posio da pea 1,
(3) Posio da pea 2, etc...
A situao objetivo (ver Figura 15.4) definida pela clusula
objetivo( [ 2/2, 1/3, 2/3, 3/3, 3/2, 3/1, 2/1, 1/1, 1/2 ] ).
Uma relao auxiliar usada no programa d(S1, S2, D), onde D a distncia horizontal entre S1 e S2,
somada com a distncia vertical entre essas mesmas posies. Queremos minimizar o tamanho das
solues, logo definiremos o custo de todos os arcos no espao de estados como sendo igual a 1. No
programa da Figura 15.5 definimos, como posies iniciais, os estados apresentados a seguir.
159
2 1 6
4 8
7 5 3
1 2 3
8 4
7 6 5
(a) (b) (c) objetivo
1 3 4
8 2
7 6 5
2 8 3
1 4 6
7 5
Figura 15.4: Trs posies iniciais para atingir um objetivo:
(a) requer 4 movimentos, (b) requer 5 movimentos e (c) requer 18 movimentos.
No programa apresentado na Figura 15.5, a funo heurstica, h, definida por meio da relao h(Pos,
H), onde Pos uma posio do jogo e H a combinao de dois fatores:
(1) disTot: a distncia total das oito peas em Pos s suas casas correspondentes na situao
objetivo. Por exemplo, na posio inicial apresentada na Figura 15.4, disTot = 4.
(2) seq: o "escore de sequncia", que mede o grau de ordenao das peas na posio corrente
em relao ordem estabelecida na configurao objetivo. seq computado pela soma dos es-
cores de todas as peas de acordo com as seguintes regras:
Uma pea no centro do tabuleiro tem escore 1;
Uma pea em uma posio no-central tem escore 0 se seguida pelo seu sucessor apro-
priado, em sentido horrio;
Em qualquer outra situao, uma pea tem escore 2.
Por exemplo, para a posio inicial apresentada na Figura 15.4, seq = 6.
A estimativa heurstica, H, computada por:
H = disTot + 3*seq
Essa funo heurstica funciona bem, no sentido em que dirige, de maneira muito eficiente, a pesquisa
para o objetivo estabelecido. Por exemplo, na soluo do jogo proposto pelas configuraes iniciais
apresentadas na Figura 15.4(a) e (b), nenhum nodo expandido alm dos que compem o caminho
mais curto para a soluo. Isso significa que as solues timas, nesses dois casos so encontradas
diretamente, sem necessidade de backtracking. Mesmo o problema mais difcil, proposto na Figura
15.4(c) solucionado quase que diretamente. Um problema com essa heurstica, entretanto, que ela
no garante que a soluo tima ser encontrada sempre antes de qualquer outra soluo mais longa.
A funo h no satisfaz a condio de admissibilidade: h h* para todos os nodos do espao de esta-
dos. Por exemplo, na posio inicial da Figura 15.4(a) temos:
h = 4 + 3*6 = 22
e
h* = 4
Por outro lado, a medida de distncia total admissvel, pois para todas as posies vale:
disTot h*
Essa relao pode ser facilmente demonstrada por meio do seguinte argumento: Se simplificassemos o
problema, permitindo s peas passar umas por cima das outras, ento cada pea poderia alcanar sua
casa-objetivo seguindo uma trajetria cuja distncia exatamente a soma da sua distncia horizontal
com a distncia vertical at esse objetivo. Ento a soluo tima seria exatamente do tamanho com-
putado por disTot. No problema original, entretanto, h interao entre as peas, que se encontram
umas nos caminhos das outras. Isso evita que as peas possam ser movidas ao longo de suas trajetri-
as mais curtas, o que assegura que o tamanho da soluo tima encontrada ser sempre maior ou igual
a disTot.
160
s([Vazio | L], [T | L1], 1) :-
move(Vazio, T, L, L1).
move(E, T, [T | L], [E | L]) :-
d(E, T, 1).
move(E, T, [T1 | L], [T1 | L1]) :-
move(E, T, L, L1).
d(X/Y, X1/Y1, D) :-
dif(X, X1, Dx),
dif(Y, Y1, Dy),
D is Dx + Dy.
dif(A, B, D) :-
D is A - B, D >=0, !;
D is B - A.
h([Vazio | L], H) :-
objetivo([Vazio | G]),
disTot(L, G, D),
seq(L, S), H is D + 3*S.
disTot([], [], 0).
disTot([T | L], [T1 | L1], D) :-
d(T, T1, D), disTot(L, L1, D2), D is D1+D2.
seq([Prim | L], S) :-
seq([Prim | L], Prim, S).
seq([T1, T2 | L], Prim, S) :-
escore(T1,T2,S1),
seq([T2 | L], Prim,S2), S is S1+S2.
seq([Ult], Prim, S) :-
escore(Ult, Prim, S).
escore(2/2, _, 1) :- !. escore(1/3, 2/3, 0) :- !.
escore(2/3, 3/3, 0) :- !. escore(3/3, 3/2, 0) :- !.
escore(3/2, 3/1, 0) :- !. escore(3/1, 2/1, 0) :- !.
escore(2/1, 1/1, 0) :- !. escore(1/1, 1/2, 0) :- !.
escore(1/2, 1/3, 0) :- !. escore(_, _, 2).
objetivo([2/2, 1/3, 2/3, 3/3, 3/2, 3/1, 2/1, 1/1, 1/2]).
incio1([2/2, 1/3, 3/2, 2/3, 3/3, 3/1, 2/1, 1/1, 1/2 ]).
incio2([2/1, 1/2, 1/3, 3/3, 3/2, 3/1, 2/2, 1/1, 2/3]).
incio3([2/2, 2/3, 1/3, 3/1, 1/2, 2/1, 3/3, 1/1, 3/2]).
mostraSol([]).
mostraSol([P | L]) :-
mostraSol(L),
nl, write('---'),
mostraPos(P).
mostraPos( [ S0, S1, S2, S3, S4, S5, S6, S7, S8 ] ) :-
membro(Y, [3, 2, 1]), membro(X, [1, 2, 3]),
membro(P-X/Y, [' '-S0, 1-S1, 2-S2, 3-S3, 4-S4
5-S5, 6-S6, 7-S7, 8-S8] ),
nl, write(P), fail.
mostraPos(_).
Figura 15.5: Procedimentos especficos para o jogo do oito.
RESUMO
Informaes heursticas podem ser usadas para estimar a distncia entre um nodo e um objetivo
em um espao de estados. Neste captulo considerou-se estimativas heursticas numricas;
O princpio da pesquisa heurstica orienta o processo de pesquisa de forma que o nodo expan-
dido sempre o mais promissor, de acordo com a estimativa heurstica;
O algoritmo de pesquisa heurstica A*, que adota esse princpio, foi implementado na Figura
15.3;
Para usar o algoritmo A* na soluo de problemas concretos, um espao de estados e uma fun-
o heurstica devem ser definidos. Para problemas de grande complexidade a dificuldade resi-
de em encontrar a funo heurstica apropriada;
161
O teorema da admissibilidade ajuda a estabelecer se A*, usando uma particular funo heursti-
ca, ir sempre encontrar uma soluo tima.
EXERCCIOS
15.1 Proponha outras aplicaes para o programa de pesquisa heurstica apresentado no presente ca-
ptulo e formalize sua representao em Prolog.
15.2 Para os problemas propostos no exerccio 15.1, determine a admissibilidade da funo heurstica
escolhida.
162
16. REDUO DE PROBLEMAS E GRAFOS E/OU
Os grafos E/OU so uma representao adequada para problemas que podem ser decompostos em
subproblemas mutuamente independentes. Exemplos de tais problemas incluem a seleo de roteiros,
integrao simblica, jogos, prova automtica de teoremas, etc. No presente captulo sero desenvol-
vidos programas para a pesquisa heurstica em grafos E/OU.
16.1 REPRESENTAO DE PROBLEMAS
Nos captulos anteriores, a soluo de problemas estava centrada na representao de seu espao de
estados. Assim, um problema podia ser reduzido a encontrar um caminho adequado em um espao de
estados. Uma outra representao, a dos grafos E/OU, parece adequar-se mais naturalmente a certos
tipos de problemas, tirando partido da possibilidade de decomposio do problema original em sub-
problemas mutuamente exclusivos, que podem ser solucionados de forma independente.
Isso ser ilustrado por meio de um exemplo. Seja o problema de encontrar uma rota em um mapa ro-
dovirio entre duas cidades dadas, como ilustrado na Figura 16.1. As distncias entre as cidades so
inicialmente desconsideradas. O problema poderia, naturalmente, ser reduzido a encontrar um cami-
nho em um espao de estados, que teria a mesma aparncia do mapa, com os nodos correspondendo a
cidades, os arcos a conexes diretas entre cidades e os custos dos arcos correspondendo s distncias
entre elas. Entretanto, vamos construir outra representao, baseada em uma decomposio natural do
problema.
No mapa da Figura 16.1 h tambm um rio. Vamos assumir que h tambm duas pontes atravs das
quais o rio pode ser cruzado: Uma ponte na cidade f e outra na cidade g. Obviamente a rota dever
incluir uma dessas pontes, de modo que forosamente deve-se passar por f ou por g. Surgem ento
duas alternativas:
Para encontrar um caminho entre a e z:
(1) Encontrar um caminho de a at z via f, ou
(2) Encontrar um caminho de a at z via g.
a
b e c
d
f
g
h i
z
j
k
2
2
3
3 1
3
4
2
2
1
3 2
3
2
3
5
3
(rio)
Figura 16.1: Encontrar um roteiro de a a z em um mapa rodovirio
163
As duas alternativas dadas podem agora ser decompostas da seguinte maneira:
(1) Para encontrar um caminho de a a z via f:
1.1 Encontrar um caminho de a a f;
1.2 Encontrar um caminho de f a z.
(2) Para encontrar um caminho de a a z via g:
2.1 Encontrar um caminho de a a g;
2.2 Encontrar um caminho de g a z.
Em resumo, tem-se duas alternativas para a soluo do problema principal: (1) via f ou (2) via g.
Alm disso, cada uma dessas duas alternativas pode ser decomposta em dois subproblemas (1.1 e 1.2
ou 2.1 e 2.2 respectivamente). O que importante aqui que, em ambas as alternativas, cada um dos
subproblemas pode ser solucionado independentemente do outro. Essa decomposio pode ser repre-
sentada graficamente atravs de um grafo E/OU, como mostrado na Figura 16.2, onde os arcos in-
terligados indicam a condio E entre os subproblemas.
a - z
a-z via f a-z via g
a-f f-z a-g g-z
Figura 16.2: Representao E/OU do problema proposto na Figura 16.1
Na figura acima, os nodos correspondem a problemas ou subproblemas. Arcos interligados significam
que todos os subproblemas devem ser solucionados. Como so, entretanto, representados os nodos
objetivos em um grafo E/OU? Estes iro corresponder, nessa representao, a subproblemas triviais
ou primitivos. No exemplo dado, um subproblema desse tipo seria: "Encontrar um roteiro de a at b".
Para isso existe uma conexo direta no mapa entre as cidades a e b.
At aqui alguns conceitos importantes foram introduzidos: Um grafo E/OU um grafo direcionado,
no qual os nodos representam problemas e os arcos indicam relaes entre tais problemas. H tambm
relaes entre os prprios arcos. Essas relaes so E e OU, dependendo de termos de resolver todos
os problemas sucessores ou apenas um deles. Essa idia exemplificada na Figura 16.3.
P Q
P1 P2 P3 Q1 Q2 Q3
(a) (b)
Figura 16.3: (a) Para resolver P, resolva P1 ou P2 ou P3. (b) Para resolver Q resolva Q1 e Q2 e Q3.
Em princpio um nodo pode possuir simultaneamente alguns sucessores conectados por meio de arcos
E e outros por meio de arcos OU. Assumiremos, entretanto, que cada nodo somente possui sucessores
de um nico tipo. Todo grafo E/OU pode ser representado dessa forma atravs da introduo de arcos
164
OU auxiliares, quando necessrio. Assim um nodo a partir do qual so emitidos somente arcos E so
denominados nodos E e os que emitem apenas arcos OU so chamados nodos OU.
Na representao atravs de espaos de estado, uma soluo para um problema era dada por um cami-
nho nesse espao de estados. na representao E/OU, uma soluo tem necessariamente que incluir
todos os subproblemas decorrentes de um nodo E, de maneira que esta no representada mais por
um caminho e sim por uma rvore. Essa rvore-soluo, que denominaremos T definida da seguinte
maneira:
O problema original P a raiz da rvore T;
Se P um nodo OU, ento somente um nico dentre os seus sucessores, juntamente com a sua
particular sub-rvore soluo est em T;
Se P um nodo E, ento todos os seus sucessores, juntamente com suas sub-rvores soluo
esto em T.
A Figura 16.4 ilustra essa definio. Ali temos custos associados aos arcos, que nos permitem formu-
lar um critrio de otimizao. Podemos, por exemplo, definir o custo de uma rvore soluo como
sendo a soma dos custos de todos os seus arcos. Como normalmente estamos interessados em minimi-
zar os custos, a rvore soluo apresentada em (c) dever ser a preferida.
a
b
d e
h
c
f g
i
(a)
1 3
1 1 2 1
6 2
3
a
b
d e
h
(b)
1
1 1
6
a
h
c
f g
(c)
3
2 1
2
Figura 16.4: (a) Um grafo E/OU: d, g e h so nodos objetivos.
(b) e (c) so rvores soluo com custos 9 e 8 respectivamente
No temos, entretanto, que basear nossa medida de otimizao exclusivamente no custo dos arcos.
Algumas vezes pode ser mais natural associar os custos com os nodos ao invs de com os arcos, ou
mesmo com arcos e nodos simultaneamente. Resumindo os conceitos relacionados com a representa-
o de grafos E/OU:
165
A representao em grafos E/OU baseia-se no princpio da reduo de problemas em subpro-
blemas;
Os nodos em um grafo E/OU correspondem aos problemas. As ligaes entre os nodos corres-
pondem s relaes entre problemas;
Um nodo do qual partem ligaes OU um nodo OU. Para solucionar um nodo OU basta solu-
cionar um de seus sucessores;
Um nodo do qual partem ligaes E um nodo E. Para solucionar um nodo E deve-se solucio-
nar todos os seus sucessores;
Para um determinado grafo E/OU, um particular problema especificado atravs de duas coi-
sas:
(1) Um nodo inicial, e
(2) Uma condio de reconhecimento de nodos objetivos;
Nodos objetivos ou terminais correspondem a problemas triviais ou primitivos;
Uma soluo representada por um grafo-soluo, um subgrafo do grafo E/OU original;
A representao dos espaos de estado pode ser vista como um caso especial da representao
E/OU, na qual todos os nodos so nodos OU;
Para nos beneficiarmos da representao E/OU, os nodos relacionados a uma condio E devem
representar subproblemas que possam ser solucionados de forma mutuamente independente. O
critrio de independncia pode ser relaxado se h uma ordenao entre os subproblemas E tal
que as solues dos subproblemas anteriores no sejam destrudas na soluo dos que se suce-
dem;
Custos podem ser associados aos arcos ou aos nodos ou a ambos, para a formalizao de um
critrio de otimizao.
a-z
a-z via f
a-f f-z
a-f via d f-z via i
a-d d-f f-i i-z
a-d via b
a-b b-d
Figura 16.5: Uma soluo para o problema de roteiros da Figura 16.1
16.2 EXEMPLOS DE REPRESENTAO DE PROBLEMAS EM GRAFOS E/OU
16.2.1 O PROBLEMA DE SELEO DE ROTEIROS
166
Para encontrar o caminho mais curto no problema proposto na Figura 16.1, um grafo E/OU, incluindo
uma funo de custo, pode ser definido da seguinte maneira:
Os nodos OU so da forma X-Z, significando: encontre o caminho de X at Z;
Os nodos E so da forma X-Z via Y, significando: encontre o caminho mais curto de X at Z,
sob a restrio de que o caminho passe por Y;
Um nodo X-Z um nodo objetivo (um problema primitivo), se X e Z esto diretamente conec-
tados no mapa;
O custo de cada nodo objetivo X-Z dado pela distncia "rodoviria" entre as cidades X e Z;
O custo de todos os demais nodos (no terminais) zero.
16.2.2 O PROBLEMA DAS TORRES DE HANI
O problema das torres de Hani, mostrado na Figura 16.6 um outro exemplo clssico de uma aplica-
o efetiva do princpio de decomposio de problemas representado atravs dos grafos E/OU. Para
fins de simplicidade consideraremos uma verso reduzida do problema contendo apenas trs anis.
c
b
a a
b
c
1 2 3 1 2 3
?
Figura 16.6: O problema das Torres de Hani
Podemos enunciar o problema das Torres de Hani da seguinte maneira: H trs "estacas", 1, 2 e 3, e
trs "anis", a, b e c (sendo a o menor e c o maior). Inicialmente, todos os anis esto empilhados
ordenadamente na estaca 1. O problema transfer-los para a estaca 3, na mesma ordem original, mo-
vendo apenas um anel de cada vez e respeitando a restrio de que nenhum anel pode ser colocado
sobre outro menor do que ele. Este problema pode ser decomposto em trs subproblemas:
(1) Colocar o anel a na estaca 3;
(2) Colocar o anel b na estaca 3;
(3) Colocar o anel c na estaca 3.
Tais objetivos, entretanto, no so mutuamente independentes. Por exemplo, o anel a pode ser coloca-
do imediatamente na estaca 3, entretanto isso impedir a soluo dos outros dois subproblemas (a
menos que se desmanche a soluo do primeiro), porque o enunciado original do problema probe a
colocao de qualquer anel sobre outro menor do que ele. Por outro lado h uma ordenao conveni-
ente dos objetivos que permite a derivao de uma soluo. Essa ordenao deriva do seguinte racio-
cnio: O terceiro objetivo (anel c na estaca 3) o mais difcil, porque a movimentao do anel c est
sujeita a mais restries. Uma boa idia em casos como esse, que na maioria das vezes funciona,
tentar atingir primeiro o objetivo mais difcil. A lgica por trs deste princpio a seguinte: como os
outros objetivos so mais fceis (no sujeitos a tantas restries, possivelmente sero atingidos sem a
necessidade de desmanchar a soluo do mais difcil. A estratgia de soluo que resulta desse princ-
pio para o problema em questo :
(1) Primeiro satisfazer o objetivo: anel c na estaca 3;
167
(2) Depois, satisfazer os demais objetivos.
Mas esse primeiro objetivo no pode ser imediatamente atingido, porque na soluo inicial o anel c
no pode ser movido. Portanto necessrio primeiro possibilitar esse movimento, refinando a estrat-
gia para:
(1) Possibilitar a movimentao do anel c da estaca 1 para a estaca 3;
(2) Mover o anel c da estaca 1 para a estaca 3;
(3) Satisfazer os demais objetivos.
O anel c somente pode ser movido de 1 para 3 se tanto a como b estiverem empilhados na estaca 2.
Assim o problema inicial, de mover a, b e c para a estaca 3 fica reduzido seguinte formulao, com-
posta de trs subproblemas:
(1) Mover a e b de 1 para 2;
(2) Mover c de 1 para 3;
(3) Mover a e b de 2 para 3.
O subproblema (2) trivial (tem soluo imediata). Os outros dois subproblemas podem ser resolvi-
dos independentemente do problema (2) porque os anis a e b podem ser movidos sem considerar a
posio de c. Para resolver os problemas (1) e (3), o mesmo princpio de decomposio pode ser em-
pregado (agora a movimentao do anel b o problema mais difcil). O problema (1) pode ento ser
reduzido a trs subproblemas triviais:
Para mover a e b de 1 para 2:
(1) Mover a de 1 para 3;
(2) Mover b de 1 para 2;
(3) Mover a de 3 para 2.
A decomposio do problema restante (mover a e b de 2 para 3) fica como um exerccio para o leitor.
16.3 PROCEDIMENTOS BSICOS DE PESQUISA EM GRAFOS E/OU
O modo mais simples de pesquisar grafos E/OU em Prolog empregar o prprio mecanismo de pes-
quisa do Prolog. Isso trivial, uma vez que o significado operacional dos programas Prolog nada mais
do que um procedimento para pesquisa em grafos E/OU. Por exemplo, o grafo E/OU apresentado na
Figura 16.4 (ignorando os custos associados aos arcos), pode ser especificado por meio das seguintes
clusulas:
a :- b.
a :- c.
b :- d, e.
c :- f, g.
e :- h.
f :- h, i.
d. g. h.
Para perguntar se o problema a pode ser resolvido, simplesmente formula-se a consulta:
?- a.
e o sistema Prolog ir efetivamente pesquisar a rvore apresentada na Figura 16.4 em profundidade e
responder "sim" aps haver visitado a parte do grafo de pesquisa correspondente a rvore soluo. A
grande vantagem desta tcnica de pesquisa E/OU a sua simplicidade, entretanto ela possui algumas
desvantagens:
Somente se consegue obter respostas do tipo sim/no, e no a rvore soluo como seria dese-
168
jvel. Poder-se-ia inclusive reconstruir a rvore-soluo a partir do mecanismo de tracing, mas
essa seria uma soluo grosseira e insuficiente no caso de se desejar a rvore soluo explici-
tamente acessvel como um objeto do programa;
Programas desse tipo so difceis de estender de modo a permitir a manipulao de custos;
Se o grafo E/OU for um grafo genrico, contendo ciclos, ento a estratgia de pesquisa em pro-
fundidade do Prolog poderia entrar em um lao recursivo infinito.
Tais deficincias sero removidas gradualmente. Inicialmente definiremos uma estratgia mais ade-
quada para a pesquisa em profundidade em grafos E/OU. Para isso ser introduzida uma relao bin-
ria que ser representada pelo operador infixo "--->". Por exemplo, o nodo a, ligados ao seus dois
sucessores "OU" ser representado pela clusula:
a ---> ou:[b, c]
Os smbolos "--->" e ":" so ambos operadores infixos que podem ser definidos da seguinte maneira:
:- op(600, xfx, '--->').
e
:- op(500, xfx, ':').
de modo que o grafo E/OU da Figura 16.4 pode ser completamente especificado por meio das clusu-
las:
a ---> ou:[b, c].
b ---> e:[d, e].
c ---> e:[f, g].
e ---> ou:[h].
f ---> ou:[h, i].
objetivo(d).
objetivo(g).
objetivo(h).
A correspondente pesquisa em profundidade para grafos E/OU pode ser definida a partir dos seguintes
princpios:
Para resolver um nodo N:
(1) Se N um nodo objetivo, ento j est solucionado de forma trivial;
(2) Se N possui sucessores OU, ento solucione um deles. (Tente um de cada vez at que uma so-
luo seja encontrada);
(3) Se N possui sucessores E, ento solucione todos eles. (Tente um de cada vez at que todos es-
tejam solucionados);
(4) Se as regras acima no produzirem uma soluo, ento assuma que o problema no pode ser re-
solvido.
Um programa para executar tais regras pode ser o seguinte:
resolve(Nodo) :-
objetivo(Nodo).
resolve(Nodo) :-
Nodo ---> ou:Nodos,
membro(Nodo1, Nodos), resolve(Nodo1).
resolve(Nodo) :-
Nodo ---> e:Nodos, resolveTodos(Nodos).
resolveTodos([]).
resolveTodos([Nodo|Nodos]) :-
resolve(Nodo), resolveTodos(Nodos).
onde membro/2 a relao usual de ocorrncia em listas. O programa acima, no entanto, tem ainda as
seguintes desvantagens:
169
No produz uma rvore soluo, e
suscetvel a laos infinitos, dependendo da presena de ciclos no grafo E/OU.
Pode-se entretanto modific-lo facilmente para produzir uma rvore soluo. Para isso modifica-se a
relao resolve/1 de modo que ela passe a ter dois argumentos:
resolve(Nodo, ArvSol).
Para a representao da rvore soluo h trs casos a considerar:
(1) Se Nodo um nodo objetivo, ento a rvore soluo correspondente o prprio Nodo;
(2) Se Nodo um nodo OU, ento sua rvore soluo da forma:
Nodo ---> SubArv
onde SubArv uma rvore soluo para um dos sucessores de Nodo;
(3) Se Nodo um nodo E, ento sua rvore soluo da forma:
Nodo ---> e:SubArvs
onde SubArvs a lista das rvores soluo de todos os sucessores de Nodo.
Por exemplo, para o grafo E/OU da Figura 16.4, a primeira soluo obtida a partir do nodo a repre-
sentada por:
a ---> b ---> e:[d, e ---> h]
As trs formas de uma rvore soluo correspondem s trs clusulas da relao resolve/1 original.
Assim, para modificar o programa suficiente adicionar uma rvore soluo como segundo argu-
mento de resolve/1. Na Figura 16.7 apresentado o programa resultante acrescido de um procedi-
mento adicional, mostra/2 para a apresentao de rvores soluo. Tal programa, entretanto, ainda
est sujeito a laos infinitos. Uma maneira simples de evit-los manter o acompanhamento da pro-
fundidade da pesquisa, impedindo o programa de ultrapassar um certo limite. isso obtido por meio
da introduo de um terceiro argumento na relao resolve/2:
resolve(Nodo, ArvSol, ProfMax)
Como anteriormente, Nodo representa um problema a ser solucionado e ArvSol uma soluo cuja
profundidade no ultrapassa ProfMax, que a profundidade mxima permitida de pesquisa no grafo.
No caso em que ProfMax=0, nenhuma expanso adicional permitida. Por outro lado, se ProfMax>0,
ento Nodo pode ser expandido e seus sucessores sero examinados at uma profundidade limitada
em ProfMax-1. Isso pode ser facilmente incorporado ao programa da Figura 16.7. Por exemplo, a
segunda clusula de resolve/2, acrescida do novo argumento fica:
resolve(Nodo, Nodo ---> Arv, ProfMax) :-
ProfMax > 0, Nodo ---> or:Nodos,
membro(Nodo1, Nodos),
P1 is ProfMax-1, resolve(Nodo1, Arv, P1).
Esse procedimento de pesquisa em rpofundidade limitada pode tambm ser utilizado para simular a
pesquisa em amplitude. A idia aqui executar a pesquisa em profundidade de forma repetitiva, cada
vez com um limite maior de profundidade, at que uma soluo seja encontrada. Isto , tentar o pro-
blema com ProfMax=0, depois 1, depois 2, etc. Um programa que implementa essa idia :
simulaAmpl(Nodo, ArvSol) :-
tentaProf(Nodo, ArvSol, 0).
tentaProf(Nod, ArvSol, Prof) :-
resolve(Nodo, ArvSol, Prof),
Prof1 is Prof+1,
tentaProf(Nodo, ArvSol, Prof1).
resolve(Nodo, Nodo) :-
objetivo(Nodo).
resolve(Nodo, Nodo ---> Arv) :-
Nodo ---> ou:Nodos,
170
membro(Nodo1, Nodos), resolve(Nodo1, Arv).
resolve(Nodo, Nodo ---> e:Arvs) :-
Nodo ---> e:Nodos,resolveTodos(Nodos,Arvs).
resolveTodos([], []).
resolveTodos([Nodo|Nodos], [Arv|Arvs]) :-
resolve(Nodo,Arv),
resolveTodos(Nodos, Arvs).
mostra(Arv) :-
mostra(Arv, 0), !.
mostra(Nodo ---> Arv, H) :-
write(Nodo),write(--->),
H1 is H+7,mostra(Arv,H1),!.
mostra(e:[T], H) :-
mostra(T, H).
mostra(e:[T|Ts], H) :-
mostra(T, H), tab(H), mostra(e:Ts, H), !.
mostra(Nodo, H) :-
write(Nodo), nl.
Figura 16.7: Um programa para a pesquisa em profundidade em grafos E/OU
A desvantagem desse programa que ele reprete a pesquisa nos nveis superiores do grafo de pesquisa
cada vez que a profundidade limite incrementada.
16.4 PESQUISA HEURSTICA EM GRAFOS E/OU
Os procedimentos de pesquisa em grafos E/Ou apresentados na seo anterior executam sua tarefa de
forma sistemtica e exaustiva sem empregar qualquer perspectiva heurstica. Para problemas comple-
xos, tais procedimentos se apresentam ineficientes, devido complexidade combinatria do espao de
pesquisa. portanto necessrio empregar funes heursticas com o propsito de evitar as alternativas
que acabaro por se tornar improdutivas. As perspectivas heursticas que sero introduzidas na pre-
sente seo iro se basear em estimativas numricas relacionadas com a dificuldade dos problemas em
grafos E/OU. O programa que ser desenvolvido pode ser visto como uma generalizao do programa
de pesquisa heurstica em espaos de estados apresentado no captulo anterior.
Inicialmente deve-se introduzir um critrio de otimizao baseado nos custos dos arcos em um grafo
E/OU. Primeiro a representao de tais grafos ser estendida para incluir custos. Por exemplo, o grafo
E/OU da Figura 16.4 pode ser representado atravs das seguintes clusulas:
a ---> ou:[b/1, c/3]
b ---> e:[d/1, e/1].
c ---> e:[f/2, g/1].
e ---> ou:[h/6].
f ---> ou:[h/2, i/3].
objetivo(d).
objetivo(g).
objetivo(h).
O custo da rvore soluo ser definido como sendo a soma dos custos de todos os arcos na rvore. O
objetivo ser uma rvore soluo de custo mnimo. Para ilustrao empregaremos mais uma vez a
Figura 16.4.
interessante definir o custo de um nodo em grafos E/OU como sendo o custo da rvore soluo ti-
ma para esse nodo. Assim definido, o custo do nodo passa a representar a dificuldade desse nodo.
Assumiremos agora que podemos estimar os custos dos nodos no grafo E/OU, atravs de alguma fun-
o heurstica h, mesmo sem conhecer suas rvores soluo. Tais estimativas sero utilizadas para
orientar a pesquisa. O programa comear a pesquisa no nodo inicial e, atravs de expanses realiza-
das sobre os nodos j visitados, construir gradualmente uma rvore de pesquisa. Esse processo ir
construir uma rvore mesmo nos casos em que o grafo E/OU no seja uma rvore. Em tais casos o
grafo ir se desdobrar em uma rvore pela duplicao de algumas de suas partes.
171
O processo de pesquisa ir, a cada momento, selecionar para expanso a rvore candidata mais pro-
missora ao desenvolvimento da rvore soluo. A questo agora : Como a funo h usada para
estimar o quanto promissora uma certa rvore candidata? Ou o quanto promissor um determinado
nodo candidato a raiz de uma rvore soluo?
Para um determinado nodo N na rvore de pesquisa, H(N) ir denotar a sua dificuldade estimada. para
um nodo folha da rvore de pesquisa corrente, H(N) = h(N). Por outro lado, para um nodo interior
dessa rvore, no necessrio empregar a funo h diretamente porque j se possui alguma informa-
o adicional sobre ele, isto , j conhecemos os seus sucessores. Portanto, como ilustrado pela Fi-
gura 16.8, a dificuldade de um nodo OU interior pode ser dada aproximadamente por:
H(N) = min(custo(N, Ni)+H(Ni))
onde custo(N, Ni) o custo do arco entre N e Ni. A regra de minimizao se justifica pelo fato de que,
para solucionar N, deve-se solucionar um dos seus sucessores. J a dificuldade de um nodo E, N,
aproximada por:
H(N) = S(custo(N, Ni) + H(Ni))
N
N1 N2 ...
Nodo OU
custo(N, N1)
H(N) = min(custo(N,Ni)+H(Ni))
N
N1 N2 ...
Nodo E
custo(N, N1)
H(N) = (custo(N,Ni)+H(Ni))
Figura 16.8: Estimativa da dificuldade, H, de problemas em grafos E/OU
Em nosso programa de pesquisa ser mais prtico, ao invs de valores de H utilizar uma outra medida,
F, definida em termos de H da seguinte maneira: Seja M um nodo antecessor de N na rvore de pes-
quisa e custo(M, N) o custo do arco que interliga M a N. Podemos definir:
F(N) = custo(M, N) + H(N)
De acordo com isso, se M um nodo antecessor de N e N1, N2, ... so nodos sucessores de N, ento:
F(N) = custo(M, N) + min F(Ni)
se N um nodo OU, e
F(N) = custo(M, N) + S F(Ni)
se N um nodo E.
O nodo inicial (representado por S) no possui antecessor, de modo que tem o seu custo (virtual) de
chegada definido como zero. Entretanto, se h for igual a zero para todos os nodos objetivos do grafo
E/OU e uma rvore soluo tima houver sido encontrada, ento F(S) tem o custo desta rvore solu-
o, isto , a soma dos custos de todos os seus arcos. Em qualquer estgio da pesquisa, cada sucessor
de um nodo OU representa uma sub-rvore soluo alternativa. O processo de pesquisa sempre ir
escolher continuar a explorao atravs do sucessor cujo valor de F mnimo. Esse processo pode ser
acompanhado, mais uma vez, a partir da Figura 16.4. Inicialmente a rvore de pesquisa o prprio
nodo a. Depois essa rvore se expande at que uma soluo seja encontrada. A Figura 16.9 mostra
alguns momentos dessa expanso. para simplificar assumiremos que h = 0 para todos os nodos. Os
nmeros associados aos nodos na figura so os valores de F para esses nodos (que naturalmente sero
alterados durante a pesquisa, medida em que novas informaes forem se acumulando).
172
A expanso da rvore inicial de pesquisa , (A), produz a rvore (B). O nodo a um nodo OU, de
modo que temos duas rvores soluo candidatas: b e c. Como (F(b) = 1) < (F(c) = 3), a alternativa b
ser escolhida para expanso. Agora, at onde a alternativa b pode ser expandida? A expanso da
rvore escolhida pode prosseguir at que:
(1) O valor de F para o nodo b se torne maior do que o nodo c, que disputa com b a possibilidade
de ser expandido, ou
(2) Se torne claro que uma rvore soluo foi encontrada.
Na Figura 16.9, o candidato b o primeiro a ser expandido, uma vez que F(b) 3 = F(c). Inicialmente
os sucessores de b, d e e so gerados (situao C) e o valor de F para o nodo b aumentado para 3.
Uma vez que isso no excede o valor limite, a rvore com raiz em b continua a ser expandida. O nodo
d reconhecido como um nodo soluo e ento o nodo e expandido, resultando na situao D. Neste
ponto, F(b) = 9 > 3, o que interrompe a expanso da alternativa b. Isso impede que o processo perceba
que h tambm um nodo objetivo e que uma rvore soluo j foi gerada. Ao invs disso a atividade
passa agora ao nodo c. O "crdito" para a expanso de F(c) agora 9, uma vez que nesse ponto F(b) =
9. Dentro desse limite a rvore candidata de raiz c expandida at que a situao E seja atingida.
Agora o processo identifica que uma rvore soluo (que inclui os objetivos g e h) foi encontrada, e o
processo encerrado. Deve-se notar que a soluo final a mais barata das duas possveis rvores-
soluo, correspondendo apresentada na Figura 16.4 (c).
16.4.1 UM PROGRAMA DE PESQUISA HEURSTICA EM GRAFOS E/OU
Um programa que implementa as idias apresentadas na seo anterior dado na Figura 16.11
8
. Antes
de comentar os detalhes do programa iremos considerar as convenes empregadas na representao
escolhida para a rvore de pesquisa.

8
Este programa gera uma nica soluo, que garantidamente a mais barata se a funo heurstica empregada gerar valores no maiores do
que os custos reais das rvores-soluo.
A rvore de pesquisa pode ser:
arv(Nodo,F,C,SubArvs), correspondendo a uma rvore de solues candidatas;
folha(Nodo,F,C), correspondendo a uma folha de uma rvore de pesquisa;
arvSol(Nodo,F,SubArvs), correspondendo a uma rvore soluo;
folSol(Nodo,F), correspondendo a uma folha da rvore soluo.
C o custo do arco que chega a um nodo.
F = C+H, onde H a estimativa heurstica de uma rvore soluo tima cuja raiz Nodo.
As sub-rvores so sempre ordenadas de modo que:
(1) Todas as sub-rvores solucionadas se encontram no fim da lista, e
(2) As demais sub-rvores so ordenadas em ordem crescente do seu valor de F
173
a
(A)
0
a
(B)
1
b c
1 3
1 3
candidato 1 candidato 2
a
(C)
3
b c
1 3
3 3
candidato 1
candidato 2
d e
1 1
a
(D)
3
b c
1 3
9 3
candidato 1
candidato 2
d e
6
7
1 1
h
a
(E)
8
b c
1 3
9 8
f g d e
6
7
1 1
h
4
h i
1 3
1 2
Figura 16.9: Aspectos de uma pesquisa heurstica em um grafo E/OU
H diversos casos a analisar, como pode ser visto na Figura 16.10. As diferentes formas que a rvore
de pesquisa assume surgem em decorrncia das seguintes possibilidades de combinao entre o tama-
nho da rvore e o seu estado de soluo.
TAMANHO:
(1) A rvore de pesquisa formada por um nico nodo (uma folha), ou
(2) A rvore possui uma raiz que tem sub-rvores no-vazias.
ESTADO DE SOLUO:
(1) A rvore j foi considerada como solucionada ( uma rvore-soluo), ou
(2) Ela ainda uma rvore candidata a ser uma rvore-soluo.
174
Caso 1: Folha de Pesquisa
folha(N, F, C)
F = C + h(N) N
C
Caso 2: rvore de Pesquisa com sub-
rvores OU
arv(N, F, C, ou:[T1, T2, ...])
N
C
...
F1 F2
F = C + min F(Ni)
T2 T1
Caso 3: rvore de Pesquisa com sub-
rvores E
arv(N, F, C, e:[T1, T2, ...])
N
C
... F1 F2
F = C + F(Ni)
N
T2 T1
Caso 4: Folha Soluo
folSol(N, F)
F = C N
C
Caso 5: rvore Soluo com raiz em um
nodo OU
arvSol(N, F, T)
F = C + F1 N
C
F1
T1
Caso 6: rvore Soluo com raiz em um
nodo E
arvSol(N, F, e:[T1, T2, ...]) N
C
... F1 F2
F = C + F(Ni)
N
T2 T1
Figura 16.10: Representao da rvore de Pesquisa
O functor principal usado para representar a rvore de pesquisa indica uma combinao dessas possi-
bilidades, podendo ser um dos seguintes:
folha/3 arv/4 folSol/2 arvSol/3
Alm disso, a representao abrange pelo menos algumas das informaes seguintes:
O nodo raiz da rvore;
O valor da funo F para a rvore;
O custo C do arco no grafo E/OU que chega at a raiz da rvore;
A lista das sub-rvores;
A relao entre as sub-rvores (E ou OU).
A lista das sub-rvores estar sempre ordenada segundo valores crescentespara a funo F. Uma sub-
rvore pode inclusive j estar solucionada, sendo, nesse caso, acomodada no final da lista.
175
:- op(500, xfx, ':'). :- op(600, xfx, '--->').
eou(Nodo, ArvSol) :- expande(folha(Nodo,0,0), 9999, ArvSol, sim).
% Procedimento expande(Arv, Limite, NovaArv, Sol)
% Caso 1: Limite Ultrapassado.
expande(Arv, Limite, Arv, no) :- f(Arv, F), F > Limite, !.
% Caso 2: Objetivo Encontrado
expande(folha(Nodo,F,C), _, folSol(Nodo,F), sim) :- objetivo(Nodo).
% Caso 3: Expandindo uma Folha
expande(folha(Nodo,F,C), Limite, NovaArv, Sol) :-
expNodo(Nodo, C, Arv1), !, expande(Arv1,Limite,NovaArv,Sol); Sol=nunca.
% Caso 4: Expandindo uma rvore
expande(arv(N,F,C,SubArvs), Limite, NovaArv, Sol) :-
Limite1 is Limite - C, expLista( SubArvs, Limite1, NovaSubs, Sol1),
continua(Sol1, N, C, NovaSubs, Limite, NovaArv, Sol).
% Procedimento expLista(Arvs, Limite, NovaArvs, Sol) - Expande uma lista de rv.
% Arvs produzindo NovaArvs
expLista(Arvs, Limite, NovaArvs, Sol) :-
selArv(Arvs,Arv,OutrasArvs,Limite,Limite1),
expande(Arv, Limite1, NovaArv, Sol1), combina(OutrasArvs, NovaArv, Sol1, NovaArvs,Sol).
% Procedimento continua(Sol1,N,C,SubArvs,Limite,NovaArv,Sol) - Decide como continuar aps
% expandir uma lista de rvores
continua(sim, N, C, SubArvs, _, arvSol(N,F,SubArvs), sim) :- backup(SubArvs, H), F is C+H, !.
continua(nunca, _, _, _, _, _, nunca) :- !.
continua(no, N, C, SubArvs, Limite, NovaArv, Sol) :-
backup(SubArvs, H), F is C+H, !, expande(arv(N,F,C,SubArvs), Limite, NovaArv, Sol).
% Procedimento combina(Arvs,Arv,Sol1,NovaArvs,Sol) - Combina as sub-rvores expandidas em uma
% lista
combina(ou:_, Arv, sim, Arv, sim) :- !.
combina(ou:Arvs, Arv, no, ou:NovaArvs, no) :- insere(Arv, Arvs, NovaArvs), !.
combina(ou:[], _, nunca, _, nunca) :- !.
combina(ou:Arvs, _, nunca, ou:Arvs, no) :- !.
combina(e:Arvs, Arv, sim, e:[Arv|Arvs], sim) :- solTodas(Arvs), !.
combina(e:_, _, nunca, _, nunca) :- !.
combina(e:Arvs, Arv, Sol1, e:NovaArvs, no) :- insere(Arv, Arvs, NovaArvs), !.
% Procedimento expNodo(Nodo, C, Arv) - Constri uma rvore com um nodo e seus sucessores
expNodo(Nodo, C, arv(Nodo, F, C, Op:SubArvs)) :-
Nodo ---> Op:Sucessores, avalia(Sucessores, SubArvs), backup(Op:SubArvs, H), F is C+H.
avalia([], []).
avalia([Nodo/C | CustosDosNodos], Arvs) :-
h(Nodo,H), F is C+H, avalia(CustosDosNodos,Arvs1), insere(folha(Nodo,F,C),Arvs1,Arvs).
% Procedimento solTodas(Arvs) - Verifica se todas as rvores da lista esto resolvidas
solTodas([]).
solTodas([Arv | Arvs]) :- sol(Arv), solTodas(Arvs).
sol(arvSol(_,_,_)).
sol(folSol(_,_)).
% Procedimento Insere(Arv, Arvs, NovaArvs) - Insere Arv na lista Arvs, produzindo Nova Arvs
insere(T, [], [T]) :- !.
insere(T, [T1 | Ts], [T, T1 | Ts]) :- sol(T1), !.
insere(T, [T1 | Ts], [T1 | Ts1]) :- sol(T), insere(T, Ts, Ts1), !.
insere(T, [T1 | Ts], [T, T1 | Ts]) :- f(T, F), f(T1, F1), F =< F1, !.
insere(T, [T1 | Ts], [T1 | Ts1]) :- insere(T, Ts, Ts1).
f(Arv, F) :- arg(2, Arv, F).
% Procedimento backup(Arvs, F)
% Recupera o valor de F armazenado em Arvs
backup(ou:[Arv | _], F) :- f(Arv, F), !.
backup(e:[], 0) :- !.
backup(e:[Arv1 | Arvs], F) :- f(Arv1, F1), backup(e:Arvs, F2), F is F1+F2, !.
backup(Arv, F) :- f(Arv, F).
% Relao selArv(Arvs, MelhorArv, Outras, Lim, Lim1) - Seleciona a melhor rvore, MelhorArv,
% de uma lista Arvs, deixando Outras. Lim o limite de expanso para Arvs e Lim1 o limite
% de expanso para MelhorArv.
selArv(Op:[Arv], Arv, Op:[], Lim, Lim) :- !.
selArv(Op:[Arv | Arvs], Arv, Op:Arvs, Lim, Lim1) :-
backup(Op:Arvs, F), (Op=ou, !, min(Lim, F, Lim1); Op=e, Lim1 is Lim-F).
min(A, B, A) :- A < B, !.
min(A, B, B).
Figura 16.11: Programa de Pesquisa Heurstica em Grafos E/OU.
176
No programa da Figura 16.11, a relao principal :
eou(Nodo, ArvSol)
onde Nodo o nodo inicial da pesquisa. O programa produz uma rvore soluo arvSol (se esta exis-
tir) que deve corresponder a uma soluo tima para o problema. Se esta ser realmente a soluo
mais barata, isso vai depender da funo heurstica h adotada pelo algoritmo. H um teorema, seme-
lhante ao teorema da admissibilidade estudado no captulo anterior, que se refere a essa dependncia.
Seja CUSTO(N) uma funo que denota o custo de uma rvore soluo mais barata para um nodo N.
Se, para cada nodo N no grafo E/OU, a estimativa heurstica h(N) CUSTO(N), ento a relao eou/2
garantidamente ir encontrar uma soluo tima. Se a funo h(N) no satisfaz a essa condio, ento
a soluo encontrada pode no ser uma soluo tima. Uma funo heurstica trivial que satisfaz a
condio de admissibilidade h = 0 para todos os nodos. A desvantagem dessa funo , naturalmen-
te, a ausncia de potencial heurstico. A relao chave acionada por eou/2
expande(Arv, Limite, Arv1, Sol)
onde Arv e Limite so argumentos de entrada e Arv1 e Sol so argumentos de sada. Seu significado
o seguinte:
Arv uma rvore de pesquisa que deve ser expandida;
Limite o limite para o valor de F que deve ser respeitado na expanso de Arv;
Sol um indicador cujo valor indica um dos seguintes trs casos:
(1) Sol=sim: Arv pode ser expandida dentro de Limite de forma a abranger uma rvore solu-
o Arv1,
(2) Sol=no: Arv pode ser expandida at Arv1, de forma que o valor de F para Arv1 exceda
Limite e no seja encontrada nenhuma sub-rvore soluo, ou
(3) Sol=nunca: Arv insolvel;
Arv1 , dependendo dos casos acima, uma rvore soluo, uma extenso de Arv cujo valor de F
ultrapassou o valor Limite ou permanecer no instanciada no caso em que Sol=nunca.
O procedimento expLista/4, definido por
expLista(Arvs, Limite, Arvs1, Sol)
similar a expande/4. Assim como em expande/4, Limite o limite de expanso de uma rvore e Sol
um indicador do que ocorreu durante a expanso (sim, no ou nunca). O primeiro argumento, entre-
tanto uma lista de rvores-E ou de rvores-OU:
Arvs = e:[T1, T2, ...] ou Arvs = ou:[T1, T2, ...]
O procedimento expLista/4 seleciona a rvore mais promissora, T (conforme os valores de F) dentre
os membros de Arvs. Devido ordenao das sub-rvores em Arv, a mais promissora ser sempre a
primeira da lista, e ser expandida com um novo limite, Limite1, que depende de Limite e tambm das
outras sub-rvores em Arvs.
Se Arvs uma lista OU, ento Limite1 corresponde ao valor de F para a prxima rvore mais promis-
sora em Arvs. Se Arvs for uma lista E, ento Limite1 Limite menos a soma dos valores de F das
rvores restantes em Arvs. O contedo de Arvs1 depende da situao indicada por Sol. No caso em
que Sol=no, Arvs1 Arvs com a sua rvore mais promissora expandida at Limite1. Quando
Sol=sim, Arvs1 uma soluo da lista Arvs encontrada antes de Limite haver sido alcanado. Se
Sol=nunca, Arvs1 no possui instanciao.
O procedimento continua/7, chamado aps a expanso de uma lista de rvores, decide o que deve ser
feito a seguir, dependendo do resultado de expLista/4: Se constri uma rvore soluo, se atualiza a
rvore de pesquisa e continua a sua expanso ou se informa "nunca" no caso em que a lista foi consi-
derada insolvel. J o procedimento
177
combina(OutrasArvs, NovaArv, Sol1, NovaArvs, Sol)
relaciona diversos objetos manipulados por expLista/4. NovaArvs a rvore expandida obtida por
expLista/4, OutrasArvs so as rvores restantes e Sol1 o estado de soluo de NovaArv. Esse proce-
dimento manipula diversos casos, dependendo de Sol1 e de se a lista de rvores do tipo OU ou E.
Por exemplo, a clusula:
combina(ou:_, Arv, sim, Arv, sim)
significa: No caso em que a lista do tipo OU e a rvore expandida foi solucionada e sua rvore solu-
o Arv, ento toda a lista foi solucionada e a sua soluo a prpria Arv. Para a apresentao de
rvores soluo pode-se definir um procedimento semelhante a mostra/2, apresentado na Figura 16.7.
A construo de tal procedimento deixada como um exerccio para o leitor.
16.4.3 UM EXEMPLO DE DEFINIO DE PROBLEMA
Vamos agora formular o problema de seleo de roteiros sob a forma de um grafo E/OU de modo que
a formulao obtida possa ser usada diretamente pelo procedimento eou/2, definido na Figura 16.11.
Assumiremos que o mapa rodovirio ser representado pela relao:
s(Cidade1, Cidade2, D)
significando que h uma ligao direta entre Cidade1 e Cidade2 a uma distncia D. Assumiremos
tambm a relao:
chave(Cidade1-Cidade2, Cidade3)
significando que, para encontrar um roteiro entre Cidade1 e Cidade2, devemos considerar somente os
caminhos que passam por Cidade3 (Cidade3 ponto de passagem obrigatrio entre Cidade1 e Cida-
de2). Por exemplo, no mapa da Figura 16.1, f e g so pontos de passagem obrigatria entre a e z:
chave(a-z, f) e chave(a-z, g)
Implementaremos ento os seguintes princpios relacionados com a seleo de roteiros:
Para encontrar um roteiro entre duas cidades, a e z
(1) Se h pontos-chaves, Y1, Y2, ..., entre a e z, encontrar:
Um roteiro de a at z passando por Y1", ou
Um roteiro de a at z passando por Y2", ou
...
(2) Se no h nenhum ponto-chave entre a e z, ento simplesmente encontre alguma cidade b, vizi-
nha de a, tal que exista um roteiro entre b e z.
Temos ento dois tipos de problemas que sero representados por:
(1) a-z: Encontre um roteiro entre a e z;
(2) a-z via y: Encontre um roteiro entre a e z passando em y.
Aqui "via" um operador infixo com prioridade superior a "-" e inferior a "--->". O grafo E/OU cor-
respondente pode agora ser implicitamente definido por:
:- op(550, xfx, via).
A-Z ---> ou:Lista :-
bagof((A-Z via Y)/0, chave(A-Z, Y), Lista), !.
A-Z ---> ou:Lista :-
bagof((Y-Z)/D, s(A, Y, D), Lista).
A-Z ---> e:[(A-Y)/0, (Y-Z)/0).
objetivo(A-A).
178
RESUMO
A representao atravs de grafos E/OU um formalismo adequado para a representao de
problemas que podem ser decompostos em subproblemas independentes;
Os nodos em um grafo E/OU podem ser nodos E ou nodos OU;
Um problema concreto definido por um nodo inicial e uma condio objetivo. A soluo de
um problema apresentada atravs de um grafo soluo;
Custos de arcos e nodos podem ser introduzidos em um grafo E/OU na modelagem de proble-
mas que exijam otimizao;
A soluo de problemas representados por meio de grafos E/OU envolvem pesquisa nesse gra-
fo. A pesquisa em profundidade executada de maneira sistemtica e fcil de programar, en-
tretanto, pode ser ineficiente em problemas complexos devido exploso combinatria;
Funes heursticas podem ser introduzidas para estimar a dificuldade dos problemas. O princ-
pio da pesquisa heurstica pode ser usado como orientao, entretanto, a implementao dessa
estratgia no to simples.
EXERCCIOS
16.1 Defina em Prolog um espao E/OU para o Problema das Torres de Hani. Use a definio en-
contrada com os procedimentos de pesquisa estudados no presente captulo.
16.2 Considere algum jogo simples para duas pessoas e escreva a sua representao E/OU. Use um
programa de pesquisa em profundidade em grafos E/OU para encontrar estratgias vitoriosas sob
a forma de rvores E/OU.
179
APNDICE A
FUNDAMENTOS TERICOS DA
PROGRAMAO EM LGICA
O presente texto apresenta a eoluao ordenada dos conceitos associados a Programaao em Lgica,
inclusie desenolendo as semanticas Modelo e Proa-1eorticas. Seu objetio oerecer ao leitor uma
isao abrangente das idias undamentais que sustentam a Programaao em Lgica, ensejando a indagaao
cientica e o desenolimento de noos estudos nessa area.
A.1 PROGRAMAO EM LGICA DE PRIMEIRA ORDEM
A.1.1 PROGRAMAS EM LGICA
Um programa em lgica constitudo por sentenas que expressam o conhecimento relevante para o
problema que se pretende solucionar. A formulao de tal conhecimento emprega dois conceitos bsi-
cos: a existncia de objetos discretos, que denominaremos indivduos, e a existncia de relaes entre
eles. Os indivduos, considerados no contexto de um problema particular, constituem o domnio do
problema. Por exemplo, se o problema solucionar uma equao algbrica, ento o domnio deve
incluir pelo menos os nmeros reais.
Para que possam ser representados por meio de um sistema simblico tal como a lgica, tanto os indi-
vduos quanto as relaes devem receber nomes. A atribuio de nomes , entretanto, apenas uma
tarefa preliminar na criao de modelos simblicos para a representao de conhecimento. A tarefa
principal a construo de sentenas expressando as diversas propriedades lgicas das relaes no-
meadas. O raciocnio sobre algum problema baseado no domnio representado obtido atravs da
manipulao de de tais sentenas por meio de inferncia lgica. Em um ambiente tpico de programa-
o em lgica, o programador estabelece sentenas lgicas que, reunidas, formam um programa. O
computador ento executa as inferncias necessrias para a soluo dos problemas propostos.
A lgica de primeira ordem possui dois aspectos: sinttico e semntico. O aspecto sinttico diz res-
peito s frmulas bem-formadas (fbfs) admitidas pela gramtica de uma linguagem formal. O aspecto
semntico est relacionado com o significado atribudo aos smbolos presentes nas fbfs da teoria.
Apresenta-se a seguir os principais conceitos necessrios para a definio de linguagens lgicas de
primeira ordem.
DEFINIO A1: Teoria de Primeira Ordem
Uma Teoria de Primeira Ordem (TPO) consiste em uma linguagem de primeira ordem definida sobre
um alfabeto de primeira ordem, um conjunto de axiomas e um conjunto de regras de inferncia. A
linguagem de primeira ordem consiste nas fbfs da teoria. Os axiomas e regras de inferncia so utilza-
dos para a derivao dos teoremas da teoria.
DEFINIO A2: Alfabeto de Primeira Ordem
Um Alfabeto de Primeira Ordem constitudo por sete classes de smbolos:
(i) Variveis Individuais,
(ii) Constantes Individuais,
(iii) Constantes Funcionais,
(iv) Constantes Predicativas,
(v) Conetivos,
(vi) Quantificadores, e
(vii) Smbolos de Pontuao.
180
As classes (v} a (vii) so as mesmas para todos os alfabetos, sendo denominadas smbolos lgicos. As
classes (i) a (iv) podem variar de alfabeto para alfabeto e so denominadas smbolos no-lgicos. Para
qualquer alfabeto de primeira ordem, somente as classes (ii) e (iii) podem ser vazias. Adotaremos aqui
as seguintes convenes para a notao dos smbolos do alfabeto: As variveis individuais sero de-
notadas por cadeias de smbolos iniciando com letras minsculas (a, b, ..., z). Os conetivos so: , ,
, , e . Os quantificadores so e . Os smbolos de pontuao so '(', ')' e ','. Adotaremos a se-
guinte hierarquia para a precedncia entre conetivos e quantificadores. Em ordem decrescente:
, ,

,
DEFINIO A3: Termo
Um termo definido recursivamente da seguinte maneira:
(i) Uma varivel individual um termo;
(ii) Uma constante individual um termo;
(iii) Se f uma funo n-ria e t
1
, t
2
, ..., t
n
so termos, ento f(t
1
,t
2
,...,t
n
) um termo.
DEFINIO A4: Frmula Bem-Formada (fbf)
Uma frmula bem-formada (fbf) definida indutivamente da seguinte maneira:
(i) Se p uma constante predicativa e t
1
, t
2
, ..., t
n
so termos, ento, p(t
1
, t
2
, ..., t
n
) uma
frmula bem formada (denominada frmula atmica ou simplesmente tomo);
(ii) Se f e g so frmulas bem formadas, ento (f), (f g), (f g), (f g) e (f g) so
frmulas bem formadas;
(iii) Se f uma frmula bem formada e X uma varivel, ento (Xf) e (Xf) so frmulas
bem formadas.
Adotou-se a conveno de escrever a implicao de modo reverso, isto (f g), devido a sua conve-
nincia na representao da frma clausal, que ser descrita mais adiante. Tambm, por abuso da lin-
guagem, de agora em diante se empregar indistintamente a palavra frmula para fazer referncia a
frmulas bem formadas.
DEFINIO A5: Linguagem de Primeira Ordem
Uma linguagem de primeira ordem sobre um alfabeto de primeira ordem o conjunto de todas as
frmulas bem formadas construdas a partir dos smbolos deste alfabeto.
A semntica informal dos conetivos e quantificadores a seguinte: representa a negao, a con-
juno (e), a disjuno (ou), a implicao e a equivalncia. o quantificador existencial, tal
que 'X' significa 'existe um X', enquanto que o quantificador universal e 'X' significa 'para todo
X' ou 'qualquer que seja X'. Assim a semntica informal de X(p(X, g(X)) q(X) r(X) : 'para
todo X, se q(X) verdadeiro e r(X) falso, ento p(X,g(X)) verdadeiro'.
DEFINIO A6: Escopo de um Quantificador e Ocorrncia Ligada de uma Varivel em uma
Frmula
O escopo de X em Xf e de X em Xf f. Uma ocorrncia ligada de uma varivel em uma fr-
mula uma ocorrncia que imediatamente segue o quantificador e qualquer ocorrncia dessa mesma
varivel no escopo desse quantificador. Qualquer outra ocorrncia de varivel dita ser livre.
DEFINIO A7: Frmula Fechada
Uma frmula dita ser fechada quando no contm nenhuma ocorrncia de variveis livres.
181
DEFINIO A8: Fecho Universal e Fecho Existencial
Se f uma frmula, ento (f) denota o fecho universal de f, que a frmula fechada obtida pela
imposio de um quantificador universal a todas as variveis que ocorrem livremente em f. Da mesma
forma, (f) denota o fecho existencial de f, obtido pela imposio de um quantificador existencial a
todas as variveis que ocorrem livremente em f.
DEFINIO A9: Literal
Um literal um tomo ou a negao de um tomo. Um literal positivo um tomo, enquanto que um
literal negativo a negao de um tomo.
DEFINIO A10: Clusula
Uma clusula uma frmula do tipo: X
1
... X
s
(l
1
... l
m
), onde cada l
i
um literal e X
1
, ..., X
s
so todas as variveis que ocorrem em l
1
, ..., l
m
.
Por exemplo, so clusulas:
XYZ (p(X,Z) q(X,Y) r(Y,Z))
e
XY (p(X,Y) r(f(X,Y),a))
Uma vez que as clusulas so to comuns na programao em lgica, conveniente adotar-se uma
notao clausal particular. Assim a clusula:
X1 ... Xs (a
1
... a
k
b
1
... b
n
),
onde a
1
, ..., a
k
, b
1
, ..., b
n
so tomos e X
1
, ..., X
s
so todas as variveis que ocorrem nestes tomos, ser
representada por:
a
1
, ..., a
k
b
1
, ..., b
n
Na notao clausal, todas as variveis so assumidas universalmente quantificadas. As vrgulas no
antecedente, b
1
, ..., b
n
, denotam conjuno, enquanto que as vrgulas no conseqente, a
1
, ..., a
k
, deno-
tam disjuno. Tais convenes se justificam uma vez que:
X
1
... X
s
(a
1
... a
k
b
1
... b
n
)
equivalente a
X
1
... X
s
(a
1
... a
k
b
1
... b
n
)
DEFINIO A11: Clusula de Programa
Uma clusula de programa uma clusula do tipo a b
1
, ..., b
n
, que contm exatamente um literal
positivo. O literal positivo, a, denominado a cabea da clusula, enquanto que a conjuno de lite-
rais b
1
, ..., b
n
o corpo da mesma.
DEFINIO A12: Clusula Unitria
Uma clusula unitria uma clusula do tipo a . Isto , uma clusula de programa com o corpo
vazio.
A semntica informal de a b
1
, ..., b
n
: "para todas as possveis atribuies de cada uma das vari-
veis presentes na clusula, se b
1
, ..., b
n
so todos verdadeiros, ento a verdadeiro". Assim, se n > 0,
uma clusula de programa condicional. Por outro lado, a clusula unitria incondicional. Sua se-
mntica informal "para todas as possveis atribuies de cada uma das variveis presentes em a, a
verdadeiro".
DEFINIO A13: Programa em Lgica
Um programa em lgica um conjunto finito de clusulas de programa.
182
DEFINIO A14: Definio de um Predicado
Em um programa em lgica, o conjunto de todas as clusulas de programa que possuem o mesmo
predicado p na cabea denominado a definio do predicado p.
DEFINIO A15: Clusula Objetivo
Uma clusula objetivo uma clusula do tipo b
1
, ..., b
n
, isto , uma clusula que possui o conse-
quente vazio. Cada b
i
(i = 1, ..., n) denominado um sub-objetivo da clusula.
DEFINIO A16: Clusula vazia
A clusula vazia, denotada por , a clusula que possui tanto o antecedente quanto o conseqente
vazios. Tal clusula deve ser interpretada como uma contradio.
DEFINIO A17: Clusula de Horn
Uma clusula de Horn uma clusula de programa ou uma clusula objetivo.
As clusulas de Horn so assim denominadas em homenagem ao matemtico Alfred Horn, que pri-
meiro lhes estudou as propriedades, em 1951. Uma de suas mais importantes caractersticas que
qualquer problema solvel capaz de ser representado por meio delas, pode ser representado de tal
forma que apenas uma das clusulas seja uma clusula objetivo, enquanto que todas as restantes sero
clusulas de programa. Para um grande nmero de aplicaes da lgica, suficiente empregar o con-
texto restrito das clusulas de Horn. Na Figura A1 posicionamos as clusulas de Horn em sua relao
com a lgica matemtica, o clculo de predicados de primeira ordem e a forma clausal.
Lgica Matemtica
Clculo de Predicados de Primeira Ordem
Forma Clausal
Clusulas de Horn
Figura A.1: Supercontextos das Clusulas de Horn
A.2 SEMNTICA MODELO-TEORTICA
A.2.1 MODELOS DE PROGRAMAS EM LGICA
Para que sejamos capazes de discutir sobre a verdade ou falsidade representadas atravs de frmulas
da lgica de primeira ordem, necessrio atribuir inicialmente algum significado a cada um dos sm-
bolos nelas presentes. Os diversos conetivos e quantificadores possuem um significado fixo, entre-
tanto, o significado atribudo atribudo s constantes individuais, constantes funcionais e constantes
predicativas pode variar. Uma interpretao consiste simplesmente em algum universo de discurso,
ou domnio, sobre o qual as variveis podem assumir valores, na atribuio de um elemento desse
universo a cada constante individual, na atribuio de um mapeamento sobre o domnio a cada cons-
tante funcional, e de uma relao sobre o domnio a cada constante predicativa. Cada interpretao
especifica assim um significado para cada smbolo na frmula. Estamos particularmente interessados
em interpretaes para as quais as frmulas expressam uma declarao verdadeira. Tais interpretaes
so denominadas modelos para as frmulas. Normalmente haver alguma interpretao especial, de-
nominada interpretao pretendida, que ir especificar o significado principal dos smbolos. Natu-
183
ralmente a interpretao pretendida sempre ser um modelo. A partir de agora emprega-se os termos
constante, funo e predicado para designar respectivamente constantes individuais, constantes fun-
cionais e constantes predicativas. A lgica de primeira ordem oferece mtodos para a deduo dos
teoremas presentes em alguma teoria. Estes podem ser caracterizados como sendo as frmulas que so
consequncia lgica dos axiomas da teoria, isto , que so verdadeiras em todas as interpretaes que
so modelos para cada um dos axiomas da teoria. Em particular, cada teorema deve ser verdadeiro na
interpretao pretendida da teoria. Os sistemas de programao em lgica que so objeto do presente
estudo adotam o Princpio da Resoluo como nica regra de inferncia. Suponha-se que se deseja
provar que a frmula
Y
1
... Y
r
(b
1
... b
n
)
uma consequncia lgica de um programa P. Com esse objetivo emprega-se o Princpio da Resolu-
o por meio de um sistema de refutao, isto , a negao da frmula a ser provada adicionada aos
axiomas e uma contradio deve ser derivada. Negando-se a frmula que se deseja provar obtem-se a
clusula objetivo:
b
1
, ..., b
n
A partir dessa frmula objetivo e operando de forma top-down sobre os axiomas de P, o sistema deri-
va sucessivas clusulas objetivo. Se, em um determinado momento, for derivada a clusula vazia,
ento uma contradio foi obtida (a clusula vazia contraditria) e esse resultado assegura que
Y
1
...Y
r
(b
1
... b
n
) uma conseqncia lgica de P. De agora em diante se usar simplesmente
objetivo para designar clusulas objetivo.
Do ponto de vista da prova de teoremas, o nico interesse demonstrar a existncia da relao de
conseqncia lgica. Por outro lado, do ponto de vista da Programao em Lgica, o interesse se con-
centra muito mais sobre as ligaes que foram realizadas sobre as variveis Y
1
, ..., Y
r
, uma vez que
estas fornecem o resultado da execuo do programa. Segundo [Llo 84], a viso ideal de um sistema
de Programao em Lgica a de uma caixa preta para a computao de ligaes e o nico interesse
reside no seu comportamento de entrada e sada, isto , as operaes executadas internamente pelo
sistema deveriam ser transparentes para o programador. Infelizmente tal situao no ocorre, em mai-
or ou menor grau nos sistemas Prolog atualmente disponveis, de forma que muitos programas Prolog
somente podem ser entendidos a partir de sua interpretao operacional, devido ao emprego de cuts e
outros mecanismos extra-lgicos.
DEFINIO A18: Interpretao
Uma interpretao de uma linguagem L de primeira ordem constituda por:
(i) Um conjunto no-vazio D, denominado o Domnio da interpretao;
(ii) Para cada constante em L a atribuio de um elemento em D;
(iii) Para cada funo n-ria em L, a atribuio de um mapeamento de D
n
em D;
(iv) Para cada predicado n-rio em L a atribuio de um mapeamento de D
n
em {V, F}, isto
, de uma relao sobre D
n
.
DEFINIO A19: Atribuio de Variveis
Seja I uma interpretao de uma linguagem L de primeira ordem. Uma atribuio de variveis (com
respeito a I) uma atribuio de um elemento do domnio de I a cada uma das variveis em L.
DEFINIO A20: Atribuio de Termos
Seja I uma interpretao de uma linguagem L de primeira ordem, com domnio D, e seja A uma atri-
buio de variveis. Uma atribuio de termos (com respeito a I e A) para os termos em L definida
da seguinte maneira:
(i) A cada varivel em L dada uma atribuio de acordo com A;
(ii) A cada constante em L dada uma atribuio de acordo com I;
(iii) Se t
1
', ..., t
n
' so as atribuies dos termos t
1
, ..., t
n
e f' a atribuio de f, ento f'(t
1
', ...,
184
t
n
') a atribuio de termos f(t
1
, ..., t
n
).
DEFINIO A21: Valor Verdade de uma Frmula
Seja I uma interpretao de domnio D de uma linguagem L de primeira ordem, e seja A uma atribui-
o de variveis. Ento a uma frmula em L pode ser atribudo um valor-verdade (verdadeiro ou fal-
so, que detotaremos por F e V respectivamente) com respeito a I e a A, da seguinte maneira:
(i) Se a frmula um tomo, p(t
1
, ..., t
n
), ento o valor verdade obtido pelo clculo do
valor verdade de p'(t
1
', ..., t
n
'), onde p' o mapeamento atribudo a p por I e t
1
', ..., t
n
' a
atribuio de termos para t
1
, ..., t
n
com respeito a I e a A;
(ii) Se a frmula tem a forma f, f g, f g, f g ou f g, ento o valor verdade da
frmula dado pela tabela verdade:
(iii) Se a frmula tem a forma Xf, ento o valor verdade da frmula V se existe d D tal
que f tem valor verdade V com respeito a I e a A(X/d), onde A(X/d) A, exceto que a
X atribudo o valor d. Caso contrrio o seu valor verdade F;
(iv) Se a frmula tem a forma Xf, ento o valor verdade da frmula V se para todo d D,
f tem valor verdade V com respeito a I e a A(X/d). Caso contrrio o seu valor verdade
F.
f g f f g f g f g f g
V V F V V V V
V F F F V V F
F V V F V F F
F F V F F V V
DEFINIO A22: Modelo de uma Frmula
Seja I uma interpretao de uma linguagem L de primeira ordem e seja f uma frmula fechada de L.
Ento I um modelo para f se o valor verdade de f com respeito a I V.
DEFINIO A23: Modelo de um Conjunto de Frmulas Fechadas
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem e seja I uma inter-
pretao de L. Dizemos que I um modelo para S se I for modelo para cada uma das frmulas em
S.
DEFINIO A24: Conjunto de Frmulas Satisfatvel
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
satisfatvel, se L possui uma interpretao que um modelo para S.
DEFINIO A25: Conjunto de Frmulas Vlido
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
vlido se toda interpretao de L um modelo para S.
DEFINIO A26: Conjunto de Frmulas Insatisfatvel
Seja S um conjunto de frmulas fechadas de uma linguagem L de primeira ordem. Dizemos que S
insatisfatvel, se S no possui modelos em L. Note que {f, f} insatisfatvel, assim como a clusula
vazia, denotada por .
DEFINIO A27: Conseqncia Lgica de um Conjunto de Frmulas Fechadas
Seja S um conjunto de frmulas fechadas e seja f uma frmula fechada de uma linguagem L de pri-
meira ordem. Dizemos que f conseqncia lgica de S, isto , S |= f, se para toda interpretao I de
L, se I um modelo para S, ento I tambm um modelo para f. Note que se S = {f
1
, ..., f
n
} um
conjunto finito de frmulas fechadas, ento f conseqncia lgica de S se e somente se f f
1
...
f
n
vlida.
185
PROPOSIO A.1
Seja S um conjunto de frmulas fechadas e f uma frmula fechada de uma linguagem L de primeira
ordem. Ento f conseqncia lgica de S se e somente se S {f} insatisfatvel.
Prova:
() Vamos supor que f seja conseqncia lgica de S. Se S {f} satisfatvel, ento existe uma
interpretao I da linguagem L tal que I modelo de S {f}. Por outro lado, se f conse-
qncia lgica de S, ento I tambm modelo de f, ou seja de {f, f}, o que no possvel.
Logo S {f} insatisfatvel.
() Inversamente, vamos supor que S {f} seja insatsfatvel e seja I uma interpretao da lin-
guagem L. Suponhamos que I seja um modelo para S. Uma vez que S {f} insatisfatvel, I
no pode ser um modelo para f. Assim, I um modelo para f e portanto f conseqncia lgi-
ca de S.
Aplicando essas ltimas definies a programas em lgica, constata-se que quando se fornece um
objetivo G ao sistema com o programa P carregado, est-se pedindo ao sistema para provar que P
{G} insatisfatvel. Se G o objetivo b
1
, ..., b
n
com as variveis Y
1
, ..., Y
r
, ento a Proposio A.1
estabelece que provar que P {G} insatisfatvel equivale a provar que Y
1
... Y
r
(b
1
... b
n
)
conseqncia lgica de P. Assim o problema bsico a determinao da insatisfatibilidade de P
{G}, onde P um programa e G um objetivo. De acordo com a definio de insatisfatibilidade, isso
implica em mostrar que nenhuma interpretao de P {G} um modelo.
DEFINIO A28: Termo Bsico e tomo Bsico
Um termo bsico um termo que no contm variveis. Da mesma forma um tomo bsico um to-
mo que no contm variveis.
DEFINIO A29: Universo de Herbrand
Seja L uma linguagem de primeira ordem. O Universo de Herbrand, UL para L o conjunto de todos
os termos bsicos que podem ser obtidos a partir das constantes e funes presentes em L. No caso em
que L no possui constantes, introduz-se uma constante (por exemplo, "a") para a formao de termos
bsicos.
DEFINIO A30: Base de Herbrand
Seja L uma linguagem de primeira ordem. A Base de Herbrand, BL para L o conjunto de todos os
tomos bsicos que podem ser formados usando os predicados de L com os termos bsicos do corres-
pondente Universo de Herbrand como argumentos.
DEFINIO A31: Interpretao de Herbrand
Seja L uma linguagem de primeira ordem. Uma interpretao sobre L uma Interpretao de Her-
brand, se as seguintes condies forem satisfeitas:
(i) O domnio da interpretao o Universo de Herbrand, UL;
(ii) As constantes em L so atribudas a si prprias em UL;
(iii) Se f uma funo n-ria em L, ento a f atribudo o mapeamento de (UL)
n
em UL de-
finido por (t
1
, ..., t
n
) f(t
1
, ..., t
n
).
Nenhuma restrio feita sobre a atribuio de predicados em L de forma que diferentes interpreta-
es de Herbrand surgem quando se emprega diferentes atribuies sobre eles. Uma vez que, para as
interpretaes de Herbrand, as atribuies de constantes e funes fixa, possvel identificar uma
interpretao de Herbrand como um subconjunto da Base de Herbrand. Para toda interpretao de
Hebrand, o correspondente subconjunto da Base de Herbrand o conjunto de todos os tomos bsicos
que so verdadeiros com respeito a essa interpretao. Inversamente, dado um subconjunto arbitrrio
da Base de Herbrand, h uma interpretao de Herbrand que a ele corresponde.
186
DEFINIO A32: Modelo de Herbrand
Seja L uma linguagem de primeira ordem e S um conjunto de frmulas fechadas de L. Um Modelo de
Herbrand para S uma interpretao de Herbrand que um modelo para S.
PROPOSIO A.2
Seja S um conjunto de clusulas e suponha que S tem um modelo. Ento S tem um modelo de Her-
brand.
Prova:
Seja I uma interpretao de S. Uma interpretao de Herbrand de S, I', definida por:
I
H
= {p(t
1
, ..., t
n
) S | p(t
1
, ..., t
n
) V c.r.a I}
Segue diretamente que se I um modelo para S, ento I
H
tambm .
PROPOSIO A.3
Seja S um conjunto de clusulas. Ento S insatisfatvel se e somente se S no possui um modelo de
Herbrand.
Prova:
Se S satisfatvel, ento a Proposio A.2 demonstra que S tem um modelo de Herbrand.
A.2.2 SUBSTITUIES RESPOSTA
Conforme foi anteriormente estabelecido, o propsito principal de um sistema de programao em
lgica a computao de ligaes. Na presente seo ser introduzido o conceito de substituio res-
posta correta, que permite um entendimento declarativo da sada desejada de um programa e um ob-
jetivo.
DEFINIO A33: Substituio
Uma substituio um conjunto finito da forma {v
1
/t
1
, ..., v
n
/t
n
}, onde cada v
i
uma varivel e cada
t
i
um termo distinto de v
i
. Alm disso, as variveis v
1
, ..., v
n
devem ser distintas. Cada elemento v
i
/t
i
denominado uma ligao para v
i
. Se os t
i
so todos bsicos, ento denominada uma substituio
bsica. Se os t
i
so todos variveis, ento denominada uma substituio varivel pura.
DEFINIO A34: Expresso
Uma expresso um termo, um literal ou uma conjuno ou disjuno de literais. Uma expresso
simples um termo ou um tomo.
DEFINIO A35: Instncia de uma Expresso
Seja = {v
1
/t
1
, ..., v
n
/t
n
} uma substiruio e E uma expresso. Ento E, a instncia de E pela substi-
tuio , a expresso obtida a partir de E atravs da substituio simultnea de todas as ocorrncias
da varivel v
i
em E, pelo termo t
i
, para i = 1, ..., n. Se E bsica, ento E denominada uma instn-
cia bsica de E. Se S = {E
1
, ..., E
n
} um conjunto finito de expresses e uma substituio, ento S
denota o conjunto {E
1
, ..., E
n
}.
DEFINIO A36: Composio de Substituies
Sejam = {u
1
/s
1
, ..., u
m
/s
m
} e = {v
1
/t
1
, ..., v
n
/t
n
} duas substituies. Ento a composio a subs-
tituio obtida do conjunto {u
1
/s
1
, ..., u
m
/s
m
, v
1
/t
1
, ..., v
n
/t
n
}, retirando-se dele todas as ligaes u
i
/s
i

para as quais u
i
= s
i
e todas as ligaes v
j
/t
j
para as quais v
j
{u
1
, ..., u
m
}.
DEFINIO A37: Substituio Identidade
Substituio Identidade a substituio dada pelo conjunto vazio. Denota-se a substituio identidade
187
por . Note que E = E para todas as expresses E.
PROPOSIO A.4
Sejam , e substituies e a substituio identidade. Ento:
(i) = =
(ii) E (E) = E()
(iii) () = ()
Prova:
(i) Segue diretamente da definio de .
(ii) suficiente provar o resultado quando E uma varivel, digamos X.
Seja = {u
1
/s
1
, ..., u
m
/s
m
} e = {v
1
/t
1
, ..., v
n
/t
n
}.
Se X {u
1
, ..., u
m
} {v
1
, ..., v
n
},
ento (X) = X() = X.
Se X {u
1
, ..., u
m
}, digamos X = u
i
,
ento (X) = s
i
= X().
Se X {v
1
, ..., v
n
} \ {u
1
, ..., u
m
}, digamos X = v
j
,
ento (X) = t
j
= X().
(iii) suficiente mostrar que, se X uma varivel, ento X(()) = X(()).
De fato, X(()) = ((X)) = (X)() = X(()), em funo de (ii).
DEFINIO A38: Variantes
Sejam E e F expresses. Diz-se que E e F so variantes se existem as substituies e tais que E =
F e F = E. Diz-se tambm que E variante de F ou que F variante de E.
DEFINIO A39: Renomeao
Seja E uma expresso e V o conjunto das variveis que ocorrem em E. Uma renomeao para E uma
substituio varivel pura {X
1
/Y
1
, ..., X
n
/Y
n
} tal que {X
1
, ..., X
n
} V, os Y
i
so distintos e (V\{X
1
, ...,
X
n
}) {Y
1
, ..., Y
n
} = .
PROPOSIO A.5
Sejam E e F expresses variantes. Ento existem as substituies e s tais que E = F e F = E, onde
uma renomeao para F e uma renomeao para E.
Prova:
Uma vez que E e F so variantes, existem as substituies
1
e
1
tais que E = F
1
e F = E
1
.
Seja V o conjunto das variveis que ocorrem em E e seja a substituio obtida de s
1
atravs
da remoo de todas as ligaes da forma X/t, onde X V. Claramente ento F = E. Alm
disso, E = F
1
= E
1
, de onde segue que s deve ser uma renomeao para E.
Estaremos interessados principalmente nas substituies que unificam um conjunto de expresses,
isto , que tornam as expresses contidas em um conjunto sintaticamente idnticas. O conceito de
unificao remonta aos estudos de Herbrand em 1930, tendo sido empregado por Robinson [Rob 65]
no estabelecimento do princpio da Resoluo. O foco do presente texto se restringir a conjuntos
finitos (no-vazios) de expresses simples (termos ou tomos).
DEFINIO A40: Unificador
Seja S um conjunto finito de expresses simples. Uma substituio dita ser um unificador para S
se S nica. Um unificador dito ser um unificador mais geral (umg) para S se, para todo unifi-
cador s de S h uma substituio tal que = .
188
Segue da definio de umg que se e so ambos umg's de {E
1
, ..., E
n
}, ento E
i
variante de E
i
.
A Proposio A.5 garante ento que E
i
pode ser obtida de E
i
por simples renomeao de variveis.
DEFINIO A41: Conjunto de Desacordo
Seja S um conjunto finito de expresses simples. O conjunto de desacordo de S definido da seguinte
maneira: Localizamos a posio do smbolo mais esquerda que no o mesmo para todas as expres-
ses de S e extramos de cada uma delas a sub-expresso que inicia com tal smbolo. O conjunto de
todas as sub-expresses assim retiradas o conjunto de desacordo de S.
ALGORITMO DA UNIFICAO
(i) Faa k = 0 e
k
= ,
(ii) Se S
k
nico, ento pare:
k
um umg de S,
seno encontre o conjunto de desacordo D
k
de S
k
;
(iii) Se existem V e t em D
k
tais que V uma varivel que no ocorre em t,
ento faa
k+1
=
k
{V/t}, incremente o valor de k e volte ao passo (ii),
seno pare: S no unificvel.
Na forma apresentada acima, o algoritmo da unificao no-determinstico, uma vez que podem ser
consideradas diversas escolhas para V no passo (iii), entretanto a aplicao de quaisquer dois umg's
produzidos pelo algoritmo ir conduzir a expresses que diferem entre si somente pelo nome das vari-
veis envolvidas. Deve ficar claro tambm que o algoritmo sempre termina, uma vez que S contm um
conjunto finito de variveis e cada aplicao do passo (iii) elimina uma delas. Ainda devemos consi-
derar que no passo (iii) uma verificao feita para garantir que V no ocorre em t. Tal verificao
denominada verificao de ocorrncia (occurs check).
TEOREMA A.1 (TEOREMA DA UNIFICAO)
(a) S um conjunto unificvel de de expresses simples se e somente se o Algoritmo da Unificao
termina, retornando um umg para S.
(b) S no um conjunto unificvel de de expresses simples se e somente se o Algoritmo da Unifica-
o termina, retornando a resposta "no".
DEFINIO A42: Substituies Resposta
Seja P um programa e G um objetivo. Uma substituio resposta para P {G} uma substituio
para as variveis de G.
Entende-se que tal substituio no precisa necessriamente conter uma ligao para cada uma das
variveis em G. Em particular, se G no contm variveis, a nica substituio possvel a substitui-
o identidade.
DEFINIO A43: Substituio Resposta Correta
Seja P um programa, G um objetivo A
1
, ..., A
k
e uma substituio resposta para P {G}. Dize-
mos que uma substituio resposta correta para P {G} se ((A
1
... A
k
)) conseqncia
lgica de P.
A partir da Proposio A.1 pode-se afirmar que uma substituio resposta correta se e somente se
P {((A
1
... A
k
))} for insatisfatvel. Esta definio de substituio resposta correta captura o
sentido intuitivo de "resposta correta". Da mesma forma que fornece substituies respostas, um sis-
tema de programao em lgica pode tambm retornar com a resposta "no". Dizemos que a resposta
"no" correta, se P {G} for satisfatvel.
189
A.3 SEMNTICA PROVA-TEORTICA
A lgica clssica de primeira ordem definida pela especificao de um esquema de axiomas e regras
de inferncia. (Para as definies bsicas ver a Seo A.1).
AXIOMAS
Para todas as frmulas bem-formadas A, B e C de uma certa linguagem L da lgica de predicados de
primeira ordem:
(i) A (B A)
(ii) (A (B C)) ((A B) (A C)).
(iii) (B A) ((B A) B).
(iv) X A(X) A(t), onde t um termo livre de X em A(X), isto , nenhuma ocorrncia
livre de X em A surge no escopo de qualquer quantificador (X'), onde X' uma vari-
vel em t.
(v) (X) (A B) (A X B), onde A no contm nenhuma ocorrncia livre de X.
REGRAS DE INFERNCIA
(i)
B
B A A,
[MP - modus ponens]
(ii)
X,A,
A

[GEN - generalizao]
DEFINIO A44: Prova
Uma prova qualquer seqncia da forma A
1
, ..., A
n
onde cada A
i
ou uma instncia de um esquema
de axiomas ou deriva dos membros anteriores da seqncia por meio da aplicao de MP ou GEN.
DEFINIO A45: Teorema
Um teorema qualquer fbf que resulte de uma prova, isto , o ltimo membro de uma seqncia de
prova.
DEFINIO A46: Frame de Primeira Ordem
Um frame de primeira ordem M para uma linguagem L da lgica de primeira ordem consiste em um
domnio no vazio D, juntamente com uma funo que atribui a cada smbolo funcional n-rio f uma
funo f' de D
n
D e a cada constante relacional C, um elemento C' de
2
D
n
.
Para estabelecer a semntica da linguagem L com respeito a esse frame, utilizaremos uma funo de
atribuio g que atribui a cada varivel individual um elemento de D. A notao M (g) |= A indica que
a funo de atribuio g satisfaz a fbf A no frame M.
(i) M (g) |= C(t
0
, ..., t
n-1
) (V(t
0
, g), ..., V(t
n-1
, g)) C'
onde V(t, g) = g(t) se t uma varivel individual e em f'(V(t
0
', ..., V(t
m-1
', g)) os t
i
so da for-
ma f(t
0
', ..., t
m-1
').
(ii) M (g) |= A M (g) | A.
(iii) M (g) |= A B M (g) |= A e M (g) |= B.
(iv) M (g) |= X A M (g{d\X}) |= A,
onde g{d\X} uma funo de atribuio idntica a g, exceto para a varivel X, qual atri-
budo o valor d.
190
As condies de verdade para os demais conetivos podem ser estabelecidas a partir das seguintes
equivalncias:
(v) A B (A B)
(vi) A B A B
(vii) A B (A B) (B A)
(viii) X A X A
DEFINIO A47: Frmula Universalmente Vlida
Uma fbf A dita ser universalmente vlida se e somente se, para todo frame M e para toda funo de
atribuio g, M (g) |= A.
TEOREMA A.2: Completeza do Clculo de Predicados
Uma fbf do clculo de predicados de primeira ordem um teorema se e somente se universalmente
vlida.
191
BIBLIOGRAFIA
[AMB 87] AMBLE, T.: Logic Programming and Knowledge Engineering. Reading: Addison-
Wesley, 1987, 348p.
[AND 93] ANDREWS, J.: Prolog Frequently Asked Questions. E-Text (Internet) by ja-
mie@cs.sfu.ca. Stanford University, 1993.
[ARI 86] ARITY Corporation, The Arity Prolog Programming Manual, Arity Corporation,
1986.
[BOW 82] BOWEN, K.A.; KOWALSKI, R.A.: Amalgamating Language and Metalanguage in
Logic Programming. In: LOGIC PROGRAMMING. London: Academic Press, 1982.
366p. p.153-172.
[BOW 85] BOWEN, K.A.: Meta Level Programming and Knowledge Representation. New
Generation Compuiting, Tokyo, v.3 n.12, p.359-383, Oct. 1985.
[BOW 86] BOWEN, K.A.: Meta Level Techniques in Logic Programming. In: INTERNA-
TIONAL CONFERENCE ON ARTIFICIAL INTELLIGENCE AND ITS APPLICA-
TIONS, 1986, Singapore. Proceedings ... Amsterdam: North-Holland, 1986. p.262-271.
[BRA 86] BRATKO, I.: Prolog Programming for Artificial Intelligence. Englewood Cliffs:
Addison-Wesley, 1986. 423p.
[BRO 86b] BRODIE, M.L.; JARKE, M.: On Integrating Logic Programming and Databases. In:
EXPERT DATABASE SYSTEMS. Menlo Park: Benjamin/Cummings, 1986. 701p.
p.191-208.
[CAR 88] CARNOTA, R.J.; TESZKIEWICZ, A.D.: Sistemas Expertos y Representacin del
Conoscimiento. Buenos Aires: EBAI, 1988.
[CAS 87] CASANOVA, M.A.; GIORNO, F.A.; FURTADO, A.L..: Programao em Lgica e a
Linguagem Prolog. So Paulo: Edgard Blcher, 1987. 461p.
[CER 86] CERRO, L.F.D.: MOLOG: A System that Extends PROLOG with Modal Logic.
New Generation Computing, Tokyo, v.4, n.1, p.35-50, 1986.
[CHA 82] CHANDRA, A.K.; HAREL, D.: Horn Clauses and Fixpoint Query Hierarchy. In:
ACM SYMPOSIUM ON PRINCIPLES OF DATABASE SYSTEMS, March 1982, Los
Angeles. Proceedings ... New York: ACM, 1982. 304p. p.158-163.
[CLA 82] CLARK, K.; TRNLUND, S-A.: Logic Programming. London: Academic Press, 1982.
[CLO 84] CLOCKSIN, W.; MELLISH, C.: Programming in Prolog, Springer-Verlag, 1984.
[COE 80] COELHO, H. et al.: How to Solve it in Prolog. Lisboa: LNEC, Universidade Nova de
Lisboa, 1980.
[DAH 83] DAHL, V.: Logic Programming as a Representation of Knowledge. Computer, Los
Alamitos, v.16, n.10, p.106-111, Oct. 1983.
[DAT 83] DATE, C.J.: An Introduction to Database Systems. 3rd. Edition. Reading: Addison-
Wesley, 1983. 513p.
[DOD 90] DODD, T.: Prolog: A Logical Approach. New York: Oxford University Press, 1990.
556p.
[FIS 87] FISCHLER, M.; FIRSCHEIN, O.: The Eye, The Brain and The Computer. Reading:
Addison-Wesley, 1987. 331p.
192
[FUR 84] FURUKAWA, K. et al.: Mandala: A Logic Based Programming System. In: IN-
RTERNATIONAL CONFERENCE ON FIFTH GENERATION COMPUTER SYS-
TEMS, 1984, Tokyo. Proceedings ... Amsterdam: North-Holland, 1984. 703p. p.613-622.
[GAL 78] GALLAIRE, H.; MINKER, J.: Logic and Databases. New York: Plenum Press, 1978.
[GAL 83] GALLAIRE, H.: Logic Databases vs, Deductive Databases. In LOGIC PROGRAM-
MING WORKSHOP '83, 1983, Albufeira, Portugal. Proceedings ... Amsterdam: North-
Holland, 1983.
[GAL 84] GALLAIRE, H.; MINKER, J.; NICOLAS, J.-M.: Logic and Databases: A Deductive
Approach. Computing Surveys, New York, v.16, n.2, p.153-185, Jun. 1984.
[GD 31] GDEL, K.: ber Formal Unentscheidbare Satze der Principia Mathematica und
Verwandter System 1. Traduo em Ingles em: From Frege to Gdel: A Sourcebook in
Mathematical Logic. Harvard University Press, Cambridge, Mass.
[GRE 69] GREEN C.: Theorem Proving by Resolution as a Basis for Question-Answering Sys-
tems. In: MACHINE INTELLIGENCE, 4. Edimburgh: Edimburgh University Press,
1969. p.183-205.
[HOF 79] HOFSTADTER, D.: Gdel, Escher and Bach. New York: Basic Books, 1979.
[HOG 84] HOGGER, C.J.: Introduction to Logic Programming. London: Academic Press, 1984.
278p.
[ISR 83] ISRAEL, D.; BERANEK, B.: The Role of Logic in Knowledge Representation. Com-
puter, Los Alamitos, v.16, n.10, p.37-41, Oct. 1983.
[IWA 88] IWANUMA, K.; HARAO, M.: Knowledge Representation and Inference Based on
First-Order Modal Logic. In: LOGIC PROGRAMMING '88. Proceedings ... Berlin:
Springer-Verlag, 1988. p.237-251.
[JAC 86] JACKSON, P.: Introduction to Expert Systems. Reading: Addison-Wesley, 1986.
292p.
[KAN 93] KANTROWITZ, M.: Prolog Resource Guide. E-Text (Internet) by mkant+prolog-
guide@cs.cmu.edu. Carnegie-Mellon University, 1993.
[KIT 84] KITAKAMI, H.S.; MIYACHI, T.; FURUKAWA, K.: A Methodology for Implementa-
tion of a Knowledge Acquisition System. In: INTERNATIONAL SYMPOSIUM ON
LOGIC PROGRAMMING, Feb. 1984, Atlantic City. Proceedings ... New York: ACM,
1984.
[KOW 74] KOWALSKI, R.A.: Predicate Logic as a Programming Language. In: IFIP '74. Pro-
ceedings ... Amsterdam: North-Holland, 1974. p.569-574.
[KOW 75] KOWALSKI, R.A.: A Proof Procedure Using Conection Graphs. Journal of ACM,
New York, v.22, n.4, p.572-595, Apr. 1975.
[KOW 78] KOWALSKI, R.A.: Logic for Data Description. In: LOGIC AND DATABASES. New
York: Plenum Press, 1978.
[KOW 79a] KOWALSKI, R.A.: Algorithm = Logic + Control. Communications of ACM, New
York, v.22, n.7, p.424-436, Jul. 1979.
[KOW 79b] KOWALSKI, R.A.: Logic for Problem Solving. New York: Elsevier, 1979. 287p.
[LID 84] LI, D.: A Prolog Database System. Hertfordshire: Research Studies Press, 1984. 207p.
[LLO 84] LLOYD, J.W.: Foundations of Logic Programming. Berlin: Springer-Verlag, 1984.
124p.
193
[MAE 88] MAES, P.: Issues in Computational Reflection. In: META LEVEL ARCHITEC-
TURES AND REFLECTION. Amsterdam: North-Holland, 1988. 355p. p.21-36.
[MAT 89] MATTOS, N.M.: An Approach to Knowledge Basis Management. Kaiserslautern:
University of Kaiserslautern, 1989. PhD Thesis, Department of Computer Science. 255p.
[MCC 69] McCARTHY, J.; HAYES, P.J.: Some Philosophical Problems from the Standpoint of
Artificial Intelligence. In: MACHINE INTELLIGENCE, 4. Edimburgh: Edimburgh
University Press, 1969. p.463-502.
[MCC 77] McCARTHY, J.: Epistemological Problems of Artificial Intelligence. In: INTERNA-
TIONAL JOINT CONFERENCE ON ARTIFICIAL INTELLIGENCE, 5., Aug. 1977,
Cambridge, Massachusetts. Proceedings ... New York: ACM, 1977
[MCC 80] McCARTHY, J.: Circunscription: A Form of Non-Monotonic Reasoning. Artificial
Intelligence, v.13, n.1, p.27-39, 1980.
[MIN 75] MINSKI, M.: A Framework for Representing Knowledge. In: THE PSICOLOGY OF
COMPUTER VISION. New York: McGraw-Hill, 1975. p.211-280.
[MIN 82] MINSKI, M.: Why People Think Computers Can't? AI Magazine, v.3, n.1, p.2-8,
1982.
[MON 88] MONTEIRO, L..; PORTO A.: Contextual Logic Programming. Lisboa: Departamento
de Informtica, Universidade Nova de Lisboa, 1988.
[MOO 84] MOORE, R.C. A Formal Theory of Knowledge and Action. In: FORMAL THEORIES
OF THE COMMON SENSE WORLD. Norwood: Ablex, 1984. p.319-358.
[NEW 82] NEWELL, A.: The Knowledge Level. Artificial Intelligence v.18, n.1, p.87-127, 1982.
[NIL 80] NILSSON, N.J.: Principles of Artificial Intelligence. Palo Alto: Tioga, 1980.
[PAL 89] PALAZZO, L.A.M.: Rhesus: Um Modelo Experimental para Representao de Con-
hecimento. Porto Alegre: CPGCC da UFRGS, 1989. 115p.
[PAL 91] PALAZZO, L.A.M.: Representao de Conhecimento: Programao em Lgica e o
Modelo das Hiperredes. Porto Alegre: CPGCC da UFRGS, 1991. Dissertao de Mes-
trado. 291p.
[PAR 86] PARKER Jr, D.S. et al.: Logic Programming and Databases. In: EXPERT DATA-
BASE SYSTEMS. Menlo Park: Benjamin Cummings, 1986. 701p. p.35-48.
[PEN 83] PENTLAND, A.P.; FISCHLER, M.A.: A More Rational View of Logic. AI Magazine,
v.4, n.4, Winter, 1983.
[PER 82] PEREIRA, L.M.: Logic Control with Logic. In: INTERNATIONAL CONFERENCE
ON LOGIC PROGRAMMING, 1., Sept. 1982, Marseille, France. Proceedings ... Berlin:
Springer-Verlag, 1982.
[PER 88] PERLIS, D.: Meta in Logic. In: META LEVEL ARCHITECTURES AND REFLEC-
TION. Amsterdam: North-Holland, 1988. 355p. p.37-50.
[ROB 65] ROBINSON, J.A.: A Machine-Oriented Logic Based On The Resolution Principle.
Journal of ACM, New York, v.12, n.1, p.23-41, Jan. 1965.
[STE 86] STERLING, L.; SHAPIRO, E.: The Art of Prolog. Cambridge: MIT Press, 1986. 427p.
[SAK 86] SAKAKIBARA, I.: Programming in Modal Logic: An Extension of Prolog Based on
Modal Logic. In: LOGIC PROGRAMMING CONFERENCE, 5., 1986, Tokyo. Pro-
ceedings ... Berlin: Springer-Verlag, 1987.
[SHA 83] SHAPIRO, E.Y.: Logic Programming with Uncertanties: A Tool for Implementing
Rule-Based Systems. In: INTERNATIONAL JOINT CONFERENCE ON ARTIFICIAL
194
INTELLIGENCE, 8., 1983, Karlsrue. Proceedings ... L:os Altos, Calif.: Distributed by
W. Kaufmann, 1983. p.529-532.
[SHA 93] SHAPIRO, E.; WARREN, D.: The Fifth Generation Project: Personal Perspectives.
Communications of ACM, v.36, n.3, March 1993. p.48-101.
[STI 85] STICKEL, M.; TYSON, W.: An Analisys of Consecutively Bounded Depth-First
Search With Applications in Automated Deduction. In: INTERNATIONAL JOINT
CONFERENCE ON ARTIFICIAL INTELLIGENCE, 9., 1985, Los Angeles. Proceed-
ings ... Los Altos, Calif.: Distributed by M. Kaufmann, 1985. p.465-471.
[STE 86] STERLING, L.; SHAPIRO, E.: The Art of Prolog. Cambridge: MIT Press, 1986.
[TAR 75] TRNLUND, S.-A.: An Interpreter for the Programming Language Predicate
Logic. In: INTERNATIONAL JOINT CONFERENCE ON ARTIFICIAL INTELLI-
GENCE, 4., 1975, Tblisi. Proceedings ... New York: ACM, 1975. p.601-608.
[TUR 84] TURNER, R.: Logics for Artificial Intelligence. West Sussex: Ellis Horwood, 1984,
121p.

You might also like