Você está na página 1de 70

MC336 - Paradigmas de programao

Prolog

Joo Meidanis

c Copyright

2011 J. Meidanis

Contedo

Introduo

1.1

Objetos e relaes . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

Programao em Prolog

. . . . . . . . . . . . . . . . . . . . .

1.3

Fatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4

Perguntas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.5

Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.6

Conjunes

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.7

Regras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

Sintaxe e unicao

15

2.1

Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

2.2

Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.3

Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.4

Igualdade e unicao

18

. . . . . . . . . . . . . . . . . . . . . .

Aritmtica

20

Estruturas de dados e recurso

24

4.1

Estruturas como rvores

. . . . . . . . . . . . . . . . . . . . .

24

4.2

Listas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

4.3

Recurso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

4.4

Juntando listas

. . . . . . . . . . . . . . . . . . . . . . . . . .

31

4.5

Acumuladores . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

Backtracking

36

5.1

Gerando mltiplas solues . . . . . . . . . . . . . . . . . . . .

37

5.2

O corte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

5.3

Usos do corte

. . . . . . . . . . . . . . . . . . . . . . . . . . .

39

5.3.1

Conrmando a escolha certa . . . . . . . . . . . . . . .

40

5.3.2

Combinao corte-falha . . . . . . . . . . . . . . . . . .

41

5.3.3

Limitando buscas . . . . . . . . . . . . . . . . . . . . .

42

Cuidados com o corte . . . . . . . . . . . . . . . . . . . . . . .

42

5.4

e o corte

Entrada e sada de dados

46

6.1

Leitura e escrita de termos . . . . . . . . . . . . . . . . . . . .

46

6.2

Leitura e escrita de caracteres

. . . . . . . . . . . . . . . . . .

48

6.3

Ler e escrever arquivos . . . . . . . . . . . . . . . . . . . . . .

49

6.4

Carregando um banco de dados

. . . . . . . . . . . . . . . . .

50

6.5

Operadores

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

Predicados pr-denidos

53

7.1

Verdadeiros

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

7.2

Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

7.3

Banco de dados . . . . . . . . . . . . . . . . . . . . . . . . . .

54

7.4

Listas

54

7.5

Conjuntos (listas sem repeties)

. . . . . . . . . . . . . . . .

54

7.6

Outros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Estilo e depurao

56

8.1

58

Depurao . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Gramticas

60

9.1

O problema da anlise lxica . . . . . . . . . . . . . . . . . . .

60

9.2

Anlise lxica em Prolog . . . . . . . . . . . . . . . . . . . . .

62

9.3

Notao para regras gramaticais . . . . . . . . . . . . . . . . .

66

9.4

Argumentos adicionais

67

. . . . . . . . . . . . . . . . . . . . . .

Bibliograa

70

Captulo 1
Introduo

Prolog ao mesmo tempo uma linguagem descritiva e prescritiva. Ao mesmo


tempo que descreve-se

o que

deve ser feito, prescreve-se

como

isto deve ser

feito.
As presentes notas esto baseadas no livro de Clocksin e Mellish,

ming in Prolog

Program-

[1]. Basicamente, o material apresentado aqui a traduo

das partes deste livro selecionadas para a disciplina MC600.

1.1

Objetos e relaes

Prolog lida com

objetos

relaes

entre eles. A palavra objeto no tem o

mesmo sentido que em orientao a objetos, pois os objetos Prolog no tm


mtodos e no h herana. Em Prolog, objetos so apenas coisas sobre as
quais queremos raciocinar.
Prolog tem um tipo chamado

termo

que engloba todos os dados e tambm

os programas nesta linguagem.

1.2

Programao em Prolog

Um programa em Prolog composto de:

fatos sobre certos objetos

regras de inferncia

perguntas sobre os objetos

Dizemos a Prolog certos fatos e regras, e depois fazemos perguntas sobre


estes fatos e regras. Por exemplo, podemos informar Prolog sobre irms e
depois perguntar se Maria e Joana so irms. Prolog responder sim ou no
em funo do que lhe dissemos.
Prolog na verdade faz muito mais do que responder sim ou no: a linguagem
permite usar o computador como um aracbouo de fatos e regras, e proporciona meios de fazer inferncias, indo de um fato a outro, e achando os valores
das variveis que podem levar a concluses lgicas.
Prolog geralmente usada como uma linguagem interpretada. Neste curso
vamos usar o interpretador SWI-Prolog, uma implementao disponibilizada
gratuitamente. Onde pegar:

http://www.swi-prolog.org.

H para todos

os tipos de sistemas operacionais.

1.3

Fatos

Eis alguns exemplos de como se informam fatos a Prolog:

gosta(pedro, maria).
gosta(maria, pedro).
valioso(ouro).
mulher(jane).
possui(jane, ouro).
pai(pedro, maria).
entrega(romeu, livro, maria).
5

Pedro gosta de Maria


Maria gosta de Pedro
Ouro valioso
Jane mulher
Jane possui ouro
Pedro pai de Maria
Romeu entrega o livro a Maria

Observe que:

nomes de relaes e objetos iniciam-se com letra minscula

o nome da relao vem primeiro, depois vem a lista de objetos separados


por vrgula e envolta em parnteses

o ponto nal obrigatrio ao nal do fato.

predicados e os objetos a que se referem so seus


argumentos. Chamaremos de banco de dados coleo de fatos e regras que

Terminologia: relaes so

damos a Prolog para resolver um certo problema.

1.4

Perguntas

Uma pergunta em Prolog tem a forma:

?- possui(maria, livro).
Estamos perguntando se Maria possui o livro. Prolog tenta

unicar

o fato

da pergunta com os fatos do banco de dados. Dois fatos se unicam se tm o


mesmo predicado e os mesmos argumentos na mesma ordem. Se Prolog achar
um fato que unica com a pergunta, vai responder sim.

Caso contrrio,

responder no.
Perceba que a resposta no em Prolog no signica necessariamente que
o fato no verdadeiro, mas simplesmente que Prolog no consegue
o fato a partir de seu banco de dados.
Considere o banco de dados:

humano(socrates).
humano(aristoteles).
ateniense(socrates).
e a pergunta:

provar

Conra isto no seguinte exemplo.

?- ateniense(aristoteles).
Embora seja verdade que Aristteles tenha sido ateniense, no se pode provar
isto a partir dos fatos dados.

1.5

Variveis

As variveis em Prolog servem para responder questes mais elaboradas, por


exemplo Do que Maria gosta? ou ento Quem mora em Atenas?.
Variveis distingem-se dos objetos por terem nomes iniciados com letra
maiscula. Considere o seguinte banco de dados:

gosta(maria, flores).
gosta(maria, pedro).
gosta(paulo, maria).
Se zermos a pergunta:

?- gosta(maria, X).
estaremos perguntando Do que Maria gosta?. Prolog responde:

X = flores
e ca esperando por mais instrues, das quais falaremos em breve. Novamente, Prolog busca fatos que uniquem com o fato da pergunta. A diferena
que uma varivel est presente agora. Variveis no instanciadas, como
o caso de

inicialmente, unicam com qualquer termo.

Prolog examina

os fatos na ordem em que aparecem no banco de dados, e portanto o fato

gosta(maria, flores) encontrado primeiro. A varivel X unica com


flores e a partir deste momento passa a estar instanciada com o termo
flores. Prolog tambm marca a posio no banco de dados onde a unicao foi feita.

Quando Prolog encontra um fato que unica com uma pergunta, Prolog
mostra os objetos que as variveis guardam. No caso em questo, s h uma
varivel, que foi unicada com o objeto

X = flores.

flores,

ento Prolog respondeu

Neste ponto Prolog aguarda novas instrues.

Se teclarmos

ENTER, isto ser interpretado como signicando que estamos satisfeitos com
a resposta dada e Prolog interrompe a busca. Se em lugar disto teclarmos um

do
ponto onde tinha parado, tentando encontrar uma outra resposta pergunta.
ponto-e-vrgula (;) seguindo de ENTER, Prolog vai continuar sua busca

Quando Prolog comea a busca a partir de uma posio previamente mercada


ao invs de comear do incio do banco de dados, dizemos que est tentando

ressatisfazer

a pergunta.

Suponha que peamos a Prolog continuar a busca teclando ; e ENTER, ou


seja, queremos ver a pergunta satisfeita de outra forma, com outro valor para

X. Isto signica que Prolog deve agora esquecer que X vale flores e continuar
a busca com X voltando a estar no instanciada. A busca prossegue do ponto
marcado no banco de dados. O prximo fato unicante gosta(maria,
pedro). A varivel X agora instanciada a pedro e Prolog move a marca
para o fato gosta(maria, pedro), respondendo X = pedro e aguardando
mais instrues. Se pedirmos continuao com ; e ENTER, no h neste
caso mais respostas possveis, e por isso Prolog respoder no.
Vejamos rapidamente um outro exemplo sobre o mesmo banco de dados.

?- gosta(X, paulo).
X = maria ;
no

1.6

pergunta inicial
primeira resposta
no h mais respostas

Conjunes

Questes mais complexas como Ser que Pedro gosta de Maria e Maria gosta
de Pedro? podem ser feitas com conjunes. Este problema consiste de duas
metas separadas que Prolog deve tentar satisfazer, e existe uma notao para
isto na linguagem. Considere o banco de dados:

gosta(maria, chocolate).
gosta(maria, vinho).
8

gosta(pedro, vinho).
gosta(pedro, maria).
A pergunta

?- gosta(pedro, maria), gosta(maria, pedro).


signica Ser Pedro gosta de Maria

Maria gosta de Pedro?. A vrgula

pronunciada e e serve para separar um nmero qualquer de metas diferentes


que devem ser satisfeitas para responder a uma pergunta, o que se chama
de

conjuno.

Prolog tentar satisfazer as metas uma a uma. No caso em

questo, a resposta ser no, pois, embora a primeira meta seja um fato, a
segunda no pode ser provada.
Conjunes combinadas com variveis podem responder a perguntas bastante
interessantes, por exemplo: H algo de que ambos Maria e Pedro gostam?.
Isto seria escrito da seguinte forma:

?- gosta(maria, X), gosta(pedro, X).


Prolog tenta satisfazer a primeira meta; caso consiga, manter uma marca
no banco de dados no ponto onde houve unicao e tenta a segunda meta.
Se a segunda meta tambm satisfeita, Prolog coloca uma outra marca para
a segunda meta. Observe que cada meta tem sua prpria marca no banco de
dados.
Se a segunda meta falhar, Prolog tentar ressatisfazer a meta anterior (neste
caso, a primeira) a partir da marca desta meta. O caso em questo ilustrativo do que chamamos de backtracking pois os seguintes eventos ocorrem:

gosta(maria, chocolate).
chocolate em todas as ocorrncias de X

1. a primeira meta encontra o fato unicador


A varivel

na pergunta.

instanciada a

Prolog marca esta posio para a primeira meta e a

instanciao de

X.

2. a segunda meta, que virou


ciao de

gosta(pedro, chocolate) devido instan-

X, no unica com nada no banco de dados, e por isso a meta


9

falha. Prolog ento tentar ressatistazer a meta anterior do ponto onde


esta parou no banco de dados, desfazendo instanciaes associadas.
3. Na ressatisfao da primeira meta, o prximo fato unicador

gosta(maria, vinho).
Prolog move a marca para a nova posio e instancia
4. Prolog tenta a prxima meta, que agora

vinho.

gosta(pedro, vinho).

Esta

no uma ressatisfao, mas sim uma meta inteiramente nova, e portanto a busca comea do incio do banco de dados. Esta nova meta
satisfeita e Prolog coloca a marca desta meta no fato unicador.
5. Todas as metas da pergunta esto satisfeitas agora. Prolog imprime as
instanciaes de variveis:

X = vinho
e aguarda instrues.

Resumindo, cada meta tem seu prprio marcador no banco de dados, que
usado caso a meta precise ser ressatisfeita. Junto com uma unicao cam guardadas instanciaes de variveis dela resultantes, que sero desfeitas
em caso de necessidade de ressatisfao.

backtracking.

1.7
Uma

A este processo se d o nome de

Regras

regra

uma armao geral sobre objetos e seus relacionamentos. Por

exemplo, suponha que queremos representar a seguinte dependncia entre


fatos:

Pedro gosta de todo mundo que gosta de vinho,

o que pode ser reescrito como:

10

Pedro gosta de

se

gosta de vinho.

Em Prolog, regras consistem de uma

cabea

e um

corpo.

A cabea e o corpo

so conectados pelo smbolo  :- formado por dois pontos e hfen. O  :-
procuncia-se se. A dependncia acima seria escrito como:

gosta(pedro, X) :- gosta(X, vinho).


Note que regras tambm terminam com ponto nal.

gosta(pedro, X). A cabea de uma regra descreve o


denido. O corpo, no caso gosta(X, vinho), uma conjun-

A cabea desta regra


que est sendo

o de metas que devem ser satisfeitas para que a cabea seja considerada
verdadeira. Por exemplo, podemos tornar Pedro mais exigente sobre o que
ele gosta adicionando mais metas ao corpo da regra:

gosta(pedro, X) :- gosta(X, vinho), gosta(X, chocolate).


ou, em outras palavras, Pedro gosta de qualquer um que goste de vinho e
de chocolate. Ou ento, supondo que Pedro gosta de mulheres que gostam
de vinho:

gosta(pedro, X) :- mulher(X), gosta(X, vinho).


Note que a mesma varivel

escopo

de

ocorre trs vezes na regra.

a regra toda. Isto signica que quando

Dizemos que o

for instanciada, as

trs ocorrncias tero o mesmo valor.


A maneira como as regras funcionam em relao satisfao de metas
a seguinte.
da regra.

Uma meta unica com uma regra se ela unica com a cabea
Agora, para vericar a veracidade da regra, o corpo usado.

Diferentemente dos fatos, onde basta haver unicao para que a meta seja
sarisfeita, no caso de uma regra a unicao na verdade transfere a vericao
da satisfao para a conjuno de metas que formam o corpo da regra.
Vamos ilustrar este procedimento com nosso prximo exemplo, que envolve a
famlia da rainha Vitria. Usaremos o predicado

11

pais

com trs argumentos

tal que

pais(X, Y, Z)

signica que os pais de

argumento a me e o terceiro o pai de

mulher

homem

so

Z.

O segundo

X. Usaremos tambm os predicados

para indicar o sexo das pessoas.

homem(alberto).
homem(eduardo).
mulher(alice).
mulher(vitoria).
pais(eduardo, vitoria, alberto).
pais(alice, vitoria, alberto).
irma_de tal que irma_de(X, Y) seja satisfeito
Y. Dizemos que X irm de Y quando:

Deniremos agora o predicado


quando

for irm de

mulher

tem me

tem os mesmos pais de

e pai

P,

X.

Em Prolog, isto vira:

irma_de(X, Y) :mulher(X),
pais(X, M, P),
pais(Y, M, P).
Se perguntarmos:

?- irma_de(alice, eduardo).
as seguintes metas sero tentadas e os resultados podem ser vistos na Tabela 1.1, onde numeramos as variveis com ndices de acordo com a meta,

12

Tabela 1.1: Processamento da meta

irma_de(alice, eduardo).

Meta

Marca

Variveis

irma_de(alice,eduardo)

irma_de,

X1 = alice,
Y1 = eduardo

regra 1
2

mulher(alice)

mulher,

pais(alice,M1 ,P1 )

fato 1

pais,
fato 2

pais(eduardo,vitoria,alberto)

pais,

M1 = vitoria,
P1 = alberto
-

fato 1

pois, embora a mesma letra signique a mesma varivel dentro de uma regra,
em metas diferentes a mesma letra signica variveis diferentes.
Note que, ao unicar com a cabea da regra, a meta 1 deu origem a trs outras
metas, denotadas pelos nmeros 2, 3, e 4, que vieram do corpo da regra. Ao
nal, Prolog consegue satisfazer a meta principal e responde:
agora que queiramos saber

de quem

sim.

Suponha

Alice irm. A pergunta adequada seria

?- irma_de(alice, X).
O que ocorre ento est na Tabela 1.2, onde

X sem ndice

indicar a varivel

da pergunta.
Observe que

X = Y1 = eduardo

e portanto Prolog responde:

X = eduardo
e ca aguardando novas instrues. O que acontecer se pedirmos respostas
alternativas? Veja o exerccio a seguir.
Em geral, um mesmo precicado denido atravs de alguns fatos e algumas
regras.

Usaremos a palavra

clusula

para nos referirmos a fatos e regras

coletivamente.

13

Tabela 1.2: Processamento da meta

irma_de(alice, X).

Meta

Marca

Variveis

irma_de(alice,X)

irma_de,

X1 = alice,
Y1 = X

regra 1
2

mulher(alice)

mulher,

pais(alice,M1 ,P1 )

fato 1

pais,

M1 = vitoria,
P1 = alberto
Y1 = eduardo

fato 2
4

pais(Y1 ,vitoria,alberto)

pais,
fato 1

Exerccios

1. Descreva o que acontece se forem pedidas respostas alternativas no


exemplo envolvendo o predicado
tamento esperado?
predicado

dif(X,Y)

irma_de

acima.

Este o compor-

Como consertar a regra, supondo que existe um


que satisfeito quando

14

so diferentes?

Captulo 2
Sintaxe e unicao

Em Prolog h apenas um tipo, chamado de

termo, que engloba todas as cons-

trues sintticas da linguagem. Neste captulo vamos estudar com algum


detalhe este tipo e seus subtipos.
Um termo pode ser uma

2.1
As

constante, uma varivel, ou uma estrutura.

Constantes

constantes

pode ser

tomos

ou

nmeros.

Quem conhece LISP notar

uma diferena aqui: os nmeros so considerados tomos em LISP, mas em


Prolog nmeros no so tomos (embora ambos sejam constantes).
Um

tomo

livro,

indica um objeto ou uma relao. Nomes de objetos como

maria,

etc. so tomos. Nomes de tomos sempre comeam com letra mi-

nscula. Nomes de predicados so sempre atmicos tambm. Os grupos de


caracteres

?- (usado em perguntas) e :- (usado em regras) so tambm to-

mos. tomos de comprimento igual a um so os

caracteres,

que podem ser

lidos e impressos em Prolog, como veremos no captulo sobre entrada e sada.


Em relao a

nmeros,

Prolog acompanha as outras linguagens, permitindo

inteiros positivos e negativos, nmeros em ponto utuante usando ponto

15

decimal e opcionalmente expoente de dez.

Alguns exemplos de nmeros

vlidos:

0, 1, -17, 2.35, -0.27653, 10e10, 6.02e-23

2.2

Variveis

Sintaticamente, as

variveis

tm nomes cujo primeiro caractere uma le-

tra maiscula ou o sinal de sublinhado (


chamadas de variveis

annimas.

underscore )  _.

Estas ltimas so

Variveis com o mesmo nome aparecendo numa mesma clusula so a mesma


varivel, ou seja, se uma ganha um valor, este valor passa imediatamente para
as outras ocorrncias, exceto para variveis annimas. As variveis annimas
so diferentes das outras nos seguintes aspectos: (1) cada ocorrncia delas
indica uma varivel diferente, mesmo dentro de uma mesma clusula, e (2) ao
serem usadas numa pergunta, seus valores no so impressos nas respostas.
Variveis annimas so usadas quando queremos que uniquem com qualquer
termo mas no nos interessa com qual valor sero instanciadas.

2.3

Estruturas

estruturas so termos mais complexos formados por um funtor


componentes separadas por vrgula e colocadas entre parnteses.
As

seguido de
Por exem-

plo, para indicar um livro com seu ttulo e autor podemos usar a estrutura
abaixo:

livro(incidente_em_antares, verissimo)
Observe que os fatos de um banco de dados em Prolog so estruturas seguidas
de um ponto nal.

16

Estruturas podem ser aninhadas.

Se quisermos sosticar a indicao dos

livros, colocando nome e sobrenome do autor para poder diferenciar entre


vrios autores com o mesmo sobrenome, podemos usar:

livro(incidente_em_antares, autor(erico, verissimo))


Estruturas podem ser argumentos de fatos no banco de dados:

pertence(pedro, livro(incidente_em_antares, verissimo)).


O nmero de componentes de um funtor a sua
igual a zero so na verdade as constantes.

aridade.

Funtores de aridade

Quando no h argumentos, a

estrutura escrita sem os parnteses.


s vezes conveniente escrever certas estruturas na forma inxa ao invs de
prexa. Quando isto acontece, dizemos que o funtor escrito como

operador.

Um operador tem na verdade trs propriedades que devem ser especicadas:


sua posio, sua precedncia e sua associatividade. A posio pode ser prexa, inxa ou posxa. A precedncia um nmero; quanto menor for, mais
prioridade o operador ter nos clculos. A associatividade pode ser esquerda
ou direita, e indica como devem ser agrupadas subexpresses consistindo
apenas deste operador.
Por exemplo, os operadores aritmticos
inxa.

+, -, *, /

fatorial (!) em geral posxo. A precedncia de

-.

tm geralmente posio

O operador unrio de negao em geral prexo, e o operador de

maior que de

A associatividade de todos os operadores aritmticos esquerda, o que

signica que uma expresso como


no como

8/(2/2).

8/2/2

ser interpretada como

(8/2)/2

Note que Prolog diferente das outras linguagens no aspecto aritmtico, pois
uma expresso como

2 + 3

simplesmente um fato como qualquer outro.

Para a realizao de clculos aritmticos sempre necessrio usar o predicado

is

que ser visto no captulo sobre aritmtica.

17

2.4

Igualdade e unicao

Em Prolog, igualdade signica unicao. Existe um predicado inxo prdenido

para a igualdade, mas em geral seu uso pode ser substitudo pelo

uso de variveis de mesmo nome. Se no existisse, o predicado

poderia ser

denido por apenas um fato:

X = X.
Uma outra caracterstica da igualdade em Prolog, j que ela signica unicao, que ela pode causar a instanciao de algumas variveis, como temos
visto nos exemplos introdutrios.
Em geral, dada uma meta da forma

T 1 = T 2, onde T 1 e T 2 so termos quais-

quer, a deciso sobre sua igualdade feita de acordo com a Tabela 2.1. Nesta
tabela so tratados os casos onde cada termo pode ser uma constante, varivel, ou estrutura. Note que quando dizemos varivel estamos na verdade
nos referindo a variveis no instanciadas, pois para variveis instanciadas
deve se usar o valor a que esto associadas para consultar a Tabela 2.1.

T2
constante
constante

se

varivel

for

mesma
varivel

T1

estrutura

sempre;

sempre;

estrutura
causa

nunca

instanciao
causa

tornam-se liga-

sempre;

instanciao

das

instanciao

nunca

sempre;

causa

instanciao

mesmo

causa
funtor,

mesmo nmero
de

componen-

tes e cada componente igual

Tabela 2.1: Condies para que dois termos se uniquem, segundo seus subtipos.

O subtipo varivel signica varivel no instanciada.

estrutura signica estruturas com aridade maior ou igual a um.

18

O subtipo

Exerccios

1. Decida se as unicaes abaixo acontecem, e quais so as instanciaes


de variveis em caso haja unicao.

pilotos(A, londres) = pilotos(londres, paris)


pilotos(londres, A) = pilotos(londres, paris)
pilotos(A, londres) = pilotos(paris, londres)
ponto(X, Y, Z) = ponto(X1, Y1, Z1)
letra(C) = palavra(letra)
letra(C) = letra(palavra)
nome(alfa) = alfa
f(X, X) = f(a,b)
f(X, a(b,c)) = f(Z, a(Z,c))
2. Como se pode denir o predicado abaixo sem usar igualdade?

irmaos(X, Y) :pai(X, PX),


pai(Y, PY),
PX = PY.

19

Captulo 3
Aritmtica

Prolog tem uma srie de predicados pr-denidos para artimtica, que podem
ser divididos entre comparao e clculo. Vamos comear pelos de comparao.
Os predicados de comparao so inxos e comparam apenas nmeros ou
variveis instanciadas a nmeros. So eles:

=:=
=\=
<
>
=<
>=

igual
diferente
menor
maior
menor ou igual
maior ou igual

Note que em Prolog o comparador menor ou igual

=<,

e no

maioria das linguagens. Isto foi feito para liberar o predicado

<=

como na

<=, que parece

uma seta, para outros usos pelo programador. Os predicados pr-denidos


no pode ser redenidos nem podem ter fatos ou regras adicionados a eles,
por exemplo, tentar acrescentar um fato como

2 < 3.

ilegal, mesmo que

seja verdadeiro.
Para exemplicar o uso dos comparadores, considere o seguinte banco de
dados contendo os prncipes de Gales nos sculos 9 e 10, e os anos em que
reinaram. Os nomes esto em gals.

20

reinou(rhodri, 844, 878).


reinou(anarawd, 878, 916).
reinou(hywel_dda, 916, 950).
reinou(iago_ap_idwal, 950, 979).
reinou(hywal_ap_ieuaf, 979, 985).
reinou(cadwallon, 985, 986).
reinou(maredudd, 986, 999).
Quem foi o prncipe em um ano dado? A seguinte regra tenciona responder
isto.

principe(X, Y) :reinou(X, A, B),


Y >= A,
Y =< B.
Alguns usos:

?- principe(cadwallon, 986).
yes
?- principe(X, 900).
X = anarawd
yes
?- principe(X, 979).
X = iago_ap_idwal ;
X = hywel_ap_ieuaf ;
no
Para clculos aritmticos, o predicado especial pr-denido

is deve ser usado.

O seu papel transformar uma estrutura envolvendo operadores aritmticos


no resultado desta expresso. O operado

is

inxo, e de seu lado direito

deve sempre aparecer uma expresso aritmtica envolvendo apenas nmeros


ou varveis instanciadas com nmeros. Do lado esquerdo pode aparecer uma
varivel no instanciada, que ser ento instanciada com o resultado da expresso, ou pode tambm aparecer um nmero ou varivel instanciada a um

21

nmero, caso em que

is testa se o lado esquerdo e direito so iguais, servindo

assim como operador de igualdade numrica.


O predicado

is o nico que tem o poder de calcular resultados de operaes

aritmticas.
Para exemplicar, considere o seguinte banco de dados sobre a populao e a
rea de diversos pases em 1976. O predicado

pop

de um pas em milhes de pessoas, e o predicado

representar a populao

area

informar a rea de

um pas em milhes de quilmetros quadrados:

pop(eua, 203).
pop(india, 548).
pop(china, 800).
pop(brasil, 108).
area(eua, 8).
area(india, 3).
area(china, 10).
area(brasil, 8).
Para calcular a densidade populacional de um pas, escrevemos a seguinte
regra, que divide a populao pela rea:

dens(X, Y) :pop(X, P),


area(X, A),
Y is P/A.
Alguns usos:

?- dens(china, X).
X = 80
yes
?- dens(turquia, X).
no
22

Os operadores para clculos aritmticos em Prolog incluem pelo menos os


seguintes:

+
*
/
//
mod

soma
subtrao
multiplicao
diviso
diviso inteira
resto da diviso

Exerccios

1. Considere o seguinte banco de dados:

soma(5).
soma(2).
soma(2 + X).
soma(X + Y).
e a meta

soma(2 + 3)
Com quais dos fatos esta meta unica? Quais so as instanciaes de
variveis em cada caso?
2. Quais so os resultados das perguntas abaixo?

?????-

X
X
6
X
Y

is 2
is Y
is 2
= 5,
is X

+ 3.
+ Z.
* 4.
Y is X // 2.
// 2, X = 5.

23

Captulo 4
Estruturas de dados e recurso

As estruturas de Prolog so muito versteis para represetar estruturas de


dados nos programas. Neste captulo veremos alguns exemplos.

4.1

Estruturas como rvores

As estruturas podem ser desenhadas como rvores, onde o funtor ca na raiz
e os componentes so seus lhos, como na Figura 4.1.

pais
pais(carlos, bete, felipe)

carlos

bete

felipe

Figura 4.1: Estruturas como rvores.


Frases da lngua portuguesa podem ter suas sintaxes representadas por estruturas em Prolog. Um tipo de sentena muito simples, consisitindo de sujeito
e predicado (no confundir com predicado Prolog!), poderia ser:

24

sentenca(sujeito(X), predicado(verbo(Y), objeto(Z)))


Tomando a sentena Pedro ama Maria e instanciando as variveis da estrutura com palavras da sentena, camos com o resultado mostrado na
Figura 4.2.

sentenca

sujeito

sentenca

predicado

sujeito

verbo

objeto

pedro

predicado

verbo

objeto

ama

maria

Figura 4.2: Sintaxe de sentenas.


A representao de estruturas pode tambm dar uma descrio picttica das
variveis, mostrando ocorrncias de uma mesma varivel.
estrutura

f(X, g(X, a))

Por exemplo, a

poderia ser representada como na Figura 4.3. A

gura no mais uma rvore, mas sim um grafo orientado acclico.

4.2

Listas

As listas so estruturas de dados importantes em Prolog. Existem diversos


predicados pr-denidos para lidar com listas em Prolog. Existem tambm
predicados para transformar estruturas em listas e vice-versa.

25

Figura 4.3: Diagrama mostrando ocorrncias da mesma varivel.

Em Prolog, Uma lista :

lista vazia, escrita como [ ],

ou uma

ou uma estrutura com dois componentes: a

cabea

e a

cauda.

O funtor (binrio) usado para representar a estrutura de lista o ponto


 ..

Para quem conhece LISP, este funtor lembra o par-com-ponto.

Figura 4.4 vemos uma lista que seria escrita como

Na

.(a, .(b, .(c, [ ]))),


(a . (b .

em Prolog. Em LISP, esta mesma lista seria representada como

(c .

()))).
.

[]

Figura 4.4: Uma lista em Prolog.

A exemplo de LISP, Prolog tambm tem uma maneira alternativa, mais prtica, de denotar listas, que no usa o funtor  . explicitamente. Basta colocar

26

os elementos separados por vrgulas entre colchetes:

[a, b, c].

Qualquer

termo pode ser componente de uma lista, por exemplo, variveis ou outras
listas:

[o, homem, [gosta, de, pescar]]


[a, V1, b, [X, Y]]
Listas so processadas dividindo-as em cabea e cauda (exceto a lista vazia).
Para quem conhece LISP, esta diviso anloga a tomar car e cdr de uma
lista. Observe alguns exemplos:

Lista

Cabea

Cauda

[a, b, c]
a
[b, c]
[ ]
no tem
no tem
[[o, gato], sentou]
[o, gato]
[sentou]
[o, [gato, sentou]]
o
[[gato, sentou]]
[o, [gato, sentou], ali]
o
[[gato, sentou], ali]
[X + Y, x + y]
X + Y
[x + y]
Para combinar com a notao simplicada para listas, Prolog tambm tem
uma notao especial, mais intuitiva, para indicar
vertical  |:

[X|Y].

.(X, Y)

usando a barra

Esta notao muito usada para decompor uma lista

em cabea e cauda, como no exemplo abaixo, onde aparecem um banco de


dados e algumas perguntas:

p([1, 2, 3]).
p([o, gato, sentou, [no, capacho]]).
?- p([X|Y]).
X = 1 , Y = [2, 3] ;
X = o, Y = [gato, sentou, [no, capacho]] ;
no
?- p([_,_,_,[_|X]]).
X = [capacho]

27

Uma ltima observao: possvel criar estruturas que parecem listas mas
no so, por exemplo,

[cavalo|branco],

que no lista porque sua cauda

no uma lista nem a lista vazia.

Exerccios

1. Decida se as unicaes abaixo acontecem, e quais so as instanciaes


de variveis em cada caso positivo.

[X, Y, Z] = [pedro, adora, peixe]


[gato] = [X|Y]
[X, Y|Z] = [maria, aprecia, vinho]
[[a, X]|Z] = [[X, lebre], [veio, aqui]]
[anos|T] = [anos, dourados]
[vale, tudo] = [tudo, X]
[cavalo|Q] = [P|branco]
[ ] = [X|Y]

4.3

Recurso

Suponha que tenhamos uma lista de cores preferidas, por exemplo

[azul, verde, vermelho, amarelo]


e queiramos saber se uma determinada cor est nesta lista. A maneira de
fazer isto em Prolog ver se a cor est na cabea da lista; se estiver, camos
satisfeitos; se no estiver, procuramos na cauda da lista, ou seja, vericamos a
cabea da

cauda agora.

E a cabea da cauda da cauda a seguir. Se chegarmos

ao m da lista, que ser a lista vazia, falhamos: a cor no estava na lista


inicial.
Para implementar isto em Prolog, primeiramente estabelecemos que trata-se
de denir uma

relao

remos um predicado

entre objetos e listas onde eles aparecem.

member

tal que

member(X, Y)

28

Escreve-

verdadeiro quando o

termo

um elemento da lista

meiro lugar, um fato que

Y.

H duas condies a vericar.

membro de

se

Em pri-

for igual cabea de

Y,

que pode ser escrito assim:

member(X, Y) :- Y = [X|_].
ou, simplicando,

member(X, [X|_]).
Note o uso da varivel annima. Neste fato, no nos interessa o que a cauda
de

Y.

X membro de Y se X membro da cauda


de Y. Aqui entrar recurso para vericar se X est na cauda. Veja como ca:

A segunda (e ltima) regra diz que

member(X, Y) :- Y = [_|Z], member(X, Z).


ou, simplicando,

member(X, [_|Y]) :- member(X, Y).


Observe novamente o uso da varivel annima.

Nesta regra, no nos inte-

ressa o que est na cabea da lista, que foi tratada na primeira clusula do
predicado

member.

Observe ainda que trocamos

por

Y,

j que

sumiu na

simplicao.
O que escrevemos foi basicamente uma denio do predicado

member, porm

a maneira de processar perguntas de Prolog faz com que esta deniao possa
ser usada computacionalmente. Exemplos:

?- member(d, [a, b, c, d, e, f, g]).


yes
?- member(2, [3, a, d, 4]).
no
29

Para denir um predicado resursivo, preciso atentar para as

parada

e para o

caso recursivo.

No caso de

member,

condies de

h na verdade duas

condies de parada: ou achamos o objeto na lista, ou chegamos ao m dela


sem ach-lo. A primeira condio tratada pela primeira clusula, que far
a busca parar se o primeiro argumento de

member

unicar com a cabea do

segundo argumento. A segunda condio de parada ocorre quando o segundo


argumento a lista vazia, que no unica com nenhuma das clusulas e faz
o predicado falhar.
Em relao ao caso recursivo, note que a regra escrita de tal forma que
a chamada recursiva ocorre sobre uma lista

menor

que a lista dada. Assim

temos certeza de acabaremos por encontrar a lista vazia, a menos claro que
encontremos o objeto antes.
Certos cuidados devem ser tomados ao fazer denies recursivas. Um deles
evitar circularidade, por exemplo:

pai(X, Y) :- filho(Y, X).


filho(X, Y) :- pai(Y, X).
Claramente, Prolog no conseguir inferir nada a partir destas denies,
pois entrar num

loop

innito.

Outro cuidado com a ordem das clusulas na denio de um predicado.


Considere a seguinte denio:

homem(X) :- homem(Y), filho(X, Y).


homem(adao).
Ao tentar responder pergunta

?- homem(X).

loop at esgotar a memria. O predicado homem est


denido usando recurso esquerda, ou seja, a chamada recursiva a meta mais

Prolog estrar em

esquerda no corpo, gerando uma meta equivalente meta original, o que


se repetir eternamente at acabar a memria. Para consertar o predicado,
basta trocar a ordem das clusulas:

30

homem(adao).
homem(X) :- homem(Y), filho(X, Y).
Em geral, aconselhvel colocar os fatos antes das regras.

Os predicados

podem funcionar bem em chamadas com constantes, mas dar errado em


chamadas com variveis. Considere mais um exemplo:

lista([A|B]) :- lista(B).
lista([ ]).
a prpria denio de lista. Ela funciona bem com constantes:

?- lista([a, b, c, d]).
yes
?- lista([ ]).
yes
?- lista(f(1, 2, 3)).
no
Mas, se perguntarmos

?- lista(X).
Prolog entrar em

loop.

Mais uma vez, inverter a ordem das clusulas resol-

ver o problema.

4.4

Juntando listas

O predicado

append

usado para juntar duas listas formando uma terceira.

Por exemplo, verdade que

append([a, b, c], [1, 2, 3], [a, b, c, 1, 2, 3]).


31

Este predicado pode ser usado para criar uma lista que a concatenao de
duas outras:

?- append([alfa, beta], [gama, delta], X).


X = [alfa, beta, gama, delta]
Mas tambm pode ser usado de outras formas:

?- append(X, [b, c, d], [a, b, c, d]).


X = [a]
A sua denio a seguinte:

append([ ], L, L).
append([X|L1], L2, [X|L3]) :- append(L1, L2, L3).
A primeira clusula a condio de parada. A lista vazia concatenada com
qualquer lista resulta na prpria lista.

A segunda condio se apia nos

seguintes princpios:

1. O primeiro elemento da primeira lista ser tambm o primeiro elemento


da terceira lista.
2. Concatenando a cauda da primeira lista com a segunda lista resulta na
cauda da terceira lista.
3. Temos que usar o prprio

append para obter a concatenao do item 2

acima.
4. Conforme aplicamos a segunda clusula, o primeiro argumento vai diminuindo, at ser a lista vazia; logo, a recurso termina.

32

4.5

Acumuladores

Freqentemente, precisamos percorrer uma estrutura em Prolog e calcular


resultados que dependem do que j foi encontrado at o momento. A tcnica
de acumuladores consiste em utilizar um ou mais argumentos do predicado
para representar a resposta at o momento durante este percurso.
argumentos recebem o nome de

acumuladores.

Estes

listlen
listlen(L, N) satis-

No prximo exemplo mostraremos uma denio para o predicado


sem acumulador e depois com acumulador. A meta
feita quando o comprimento da lista
pr-denido

length

L igual a N. Prolog possui o predicado

para esta nalidade, mas vamos denir nossa prpria

verso. Eis a denio sem acumuladores:

listlen([ ], 0).
listlen([H|T], N) :- listlen(T, N1), N is N1 + 1.
Observe que o primeiro argumento deve vir instanciado para que esta denio funcione. A denio com acumulador baseia-se no mesmo princpio
recursivo, mas acumula a resposta a cada passo num argumento extra. Usa-

lenacc que uma generalizao de listlen. A


lenacc(L, A, N) satisfeita quando o comprimento de L adicionado
ao nmero A resulta em N. Para obter o comprimento da lista, basta chamar
lenacc com o segundo argumento igual a zero. Eis as denies:

mos um predicado auxiliar


meta

lenacc([ ], A, A).
lenacc([H|T], A, N) :- A1 is A + 1, lenacc(T, A1, N).
listlenacc(L, N) :- lenacc(L, 0, N).
Acompanhe a seqncia de submetas criadas para calcular o comprimento de

[a, b, c, d, e]:
listlenacc([a, b, c, d, e], N)
lenacc([a, b, c, d, e], 0, N)
lenacc([b, c, d, e], 1, N)
33

lenacc([c, d, e], 2, N)
lenacc([d, e], 3, N)
lenacc([e], 4, N)
lenacc([ ], 5, N)
onde todos os

so variveis distintas mas ligadas entre si no procesamento

das regras denidas. Esta ltima meta unica com a condio de parada (a

lenacc) e instancia N como 5, o que faz com que o N de

primeira clusula de

listlen

seja tambm igual a 5.

Acumuladores no precisam ser nmeros inteiros. Considere a seguinte denio do predicado

rev,

que inverte a ordem dos elementos de uma lista

(Prolog tem sua prpria verso chamada

reverse):

rev(L1, L3) :- revacc(L1, [ ], L3).


revacc([ ], L3, L3).
revacc([H|L1], L2, L3) :- revacc(L1, [H|L2], L3).
revacc serve como acumulador. Observe a seqncia de metas usadas para responder pergunta ?- rev([a, b, c, d], L3).:
O segundo argumento de

rev([a, b, c, d], L3)


revacc([a, b, c, d], [ ], L3)
revacc([b, c, d], [a], L3)
revacc([c, d], [b, a], L3)
revacc([d], [c, b, a], L3)
revacc([ ], [d, c, b, a], L3)
L3 so distintas mas ligadas. Os elementos
em L2 a cada chamada. Os elementos saem e

Nestas metas todas as variveis


vo saindo de

L1

e entrando

entram pela frente nas listas, combinando com as operaes de lista em Prolog
que s permitem manipular diretamente a cabea.
parada instancia

L3

No nal, a clusula de

reversa.

Ao lidar com acumuladores, muito importante no perder de vista o

nicado

dos predicados a denir.

sig-

Neste exemplo, essencial entender o

34

revacc: a meta revacc(L1, L2, L3)


lista L1 concatenada com a lista L2 resulta

que signica o predicado

satisfeita

quando a reversa da

em

L3.

De

posse desta denio em palavras mais fcil chegar denio em Prolog.

Exerccios

1. Escreva um predicado
o ltimo elemento da

last(L, X) que satisfeito quando o termo X


lista L.

2. Escreva um predicado

efface(L1, X, L2)

que satisfeito quando

a lista obtida pela remoo da primeira ocorrncia de


3. Escreva um predicado

delete(L1, X, L2)

em

L1.

que satisfeito quando

a lista obtida pela remoo de todas as ocorrncias de

35

X
X

em

L1.

L2
L2

Captulo 5

Backtracking e o corte
Resumindo o que vimos sobre a operao de Prolog at agora:

1. uma pergunta a conjuno de vrias metas, que chamaremos de 1, 2,


3, . . . ,

n.

Estas metas so processadas na ordem dada na tentativa de

satisfaz-las.
2. a tentativa de satisfao de uma meta

consiste numa busca no banco

de dados, a partir do incio, por uma clusula unicante. Se no houver


tal clusula, a meta falha. Se houver clusula unicante, marca-se o
ponto no banco de dados onde ela ocorre, e instanciam-se e ligam-se as
variveis conforme necessrio. Dizemos neste caso que a meta

casou.

Se a clusula unicante for um fato, a meta satisfeita. Se for a cabea


de uma regra, a meta d origem a um novo nvel de submetas, criadas a
partir da cauda da regra, que chamaremos de
de

k.1, k.2, etc.

A satisfao

agora depende da satisfao conjunta de todas as submetas.

3. quando uma meta satisfeita, passa-se para a prxima meta. Se no


houver prxima, Prolog pra e informa o resultado (positivo), juntamente com os valores das variveis da pergunta.
4. quando uma meta falha, a meta anterior sofre tentativa de ressatisfao.
Chamamos esta ao de

backtracking

(retrocesso). Se no existir meta

anterior, Prolog pra e informa o resultado (negativo) da busca.

36

5. a tentativa de ressatisfao de uma meta semelhante de satisfao,


com as seguintes ressalvas:
(a) desfazem-se as instanciaes e ligaes causadas pela ltima unicao desta meta.
(b) a busca continua do ponto marcado no banco de dados ao invs
de comear do nicio;

Neste captulo vamos examinar o processo de

backtracking

e conhecer o corte, um mecanismo especial que inibe o

com mais detalhe

backtracking

em

certas condies.
A notao  k.m para indicar metas geradas por um casamento da meta

com uma regra interessante para saber quem a meta-me de cada meta
gerada, o que vai ser importante no nosso estudo do corte. Porm, em certas
situaes, podemos preferir simplesmente usar uma numerao sequencial
para as metas, como fazem alguns depuradores de sistemas Prolog.

5.1

Gerando mltiplas solues

Considere o seguinte banco de dados.

pai(maria,
pai(pedro,
pai(sueli,
pai(jorge,

jorge).
jorge).
haroldo).
eduardo).

pai(X) :- pai(_,X).
H dois predicados

pai:

um binrio, cujos argumentos so uma pessoa e seu

pai, nesta ordem, e um unrio, que baseado no outro, e diferencia pais de


no-pais. A pergunta

?- pai(X).
37

causar o seguinte resultado:

X =
X =
X =
X =
no

jorge ;
jorge ;
haroldo ;
eduardo ;

Note que Jorge apareceu duas vezes, pois h dois fatos onde ele aparece como
pai de algum. Talvez quisssemos que cada pai aparecesse uma vez s, mas
a operao padro de Prolog causar o resultado acima.
Uma situao semelhante ocorre com o predicado

member

visto anterior-

mente, quando a lista contm repeties. Uma meta do tipo

member(a, [a, b, c, a, c, a, d, a, b, r, a])


pode ser satisfeita vrias vezes antes de falhar (no caso ilustrado, cinco vezes).
H situaes onde gostaramos que ela fosse satisfeita uma vez s. Podemos
instruir Prolog a descartar escolhas desnecessrias com o uso do corte.
As situaes mencionadas acima envolviam limitar um nmero nito de alternativas a uma s. H casos onde precisamos gerar um nmero innito de
alternativas, no porque pretendemos consider-las todas, mas porque no
sabemos de antemo quando vai aparecer a alternativa que nos interessa.
Considere a seguinte denio de predicado:

inteiro(0).
inteiro(N) :- inteiro(M), N is M + 1.
A pergunta

?- inteiro(N).
causar a gerao de todos os inteiros a partir do zero, em ordem crescente.
Isto pode ser usado em parceria com outro predicado que seleciona alguns
entre estes inteiros para uma determinada aplicao.

38

5.2

O corte

O corte um mecanismo especial em Prolog que instrui o sistema a no


reconsiderar certas alternativas ao fazer

backtracking.

Isto pode ser impor-

tante para poupar memria e tempo de processamento. Em alguns casos, o


corte pode signicar a diferena entre um programa que funciona e outro
que no funciona.
Sintaticamente, o corte um predicado denotado por  !, com zero argumentos.

Como meta, ele sempre satisfeito da primeira vez que encon-

trado, e sempre falha em qualquer tentativa de ressatisfao.

Alm disso,

como efeito colateral ele impede a ressatisfao da meta que lhe deu origem,
chamada de sua

meta me.

k . Numa tentativa
k como um todo, e
anterior a k .

Se o corte a meta

k.l, sua meta me a meta

de ressatisfao do corte, ele causa a falha da meta


o

backtracking

continua tentando ressatisfazer a meta

Vejamos um exemplo. Considere a regra

g :- a, b, c, !, d, e, f.
Prolog realiza o
sucesso de

processo de

backtracking

normalmente entre as metas

a, b

at que o

cause a satisfao do corte e Prolog passe para a meta

backtracking

acontece normalmente entre

d, e

f,

algum momento falhar, o que ocorre que a meta envolvendo


com esta regra falha imediatamente tambm.

5.3

Usos do corte

H trs usos principais do corte:

indicar que a regra certa foi encontrada

combinao corte-falha indicando negao

limitar uma busca nita ou innita

39

mas se

d. O
d em

que casou

5.3.1 Conrmando a escolha certa


Os predicados em Prolog tm em geral vrias clusulas.

Em alguns pre-

dicados, diferentes clusulas so dirigidas a diferentes padres de dados de


entrada.

s vezes possvel selecionar qual regra apropriada para cada

entrada s pela sintaxe da entrada, por exemplo, uma regra com

[X|Y]

no

casar com a lista vazia. Outras vezes, como quando os predicados envolvem
nmeros, isto no possvel. Nestes casos, o corte pode ajudar a fazer com
que a meta s case com o caso destinado a ela.
Considere a seguinte denio de um predicado

fat(N, F)

que calcula o

fatorial de um nmero:

fat(0, 1) :- !.
fat(N, F) :- N1 is N - 1, fat(N1, F1), F is F1 * N.
O corte aqui serve para impedir que uma meta da forma

fat(O, F) case com

a segunda clusula em caso de ressatisfao. Veja o que ocorre com e sem o


corte.
Com o corte:

?- fat(5, F).
F = 120 ;
no
Sem o corte:

?- fat(5, F).
F = 120 ;

loop

innito 

A denio de

fat

out of memory )

acima ainda no a melhor possvel. Veja na seo dos

exerccios o que precisa ser feito para melhor-la.

40

5.3.2 Combinao corte-falha


Existe em Prolog um predicado pr-denido sem argumentos chamado
que sempre falha.

fail

Pode-se usar em seu lugar qualquer meta incodicional-

mente falsa como por exemplo

0 > 1

mas mais claro e elegante usar

fail.

Usado em combinao com o corte, ele pode implementar negao.

nonmember(X, L) que o contrrio


de member(X, L), ou seja, satisfeito exatamente quando membar(X, L)
falha, isto , quando X no membro de L. Eis a implementao de nonmember
Suponha que precisemos de um predicado

usando corte e falha:

nonmember(X, L) :- member(X, L), !, fail.


nonmember(_, _).
nonmember(X, L), Prolog vai tentar a
member(X, L) for satisfeito, o corte ser processado
e logo a seguir vem fail. Devido ao corte, sabemos que esta tentativa de
ressatisfao vai fazer a meta nonmember(X, L) falhar sem tentar a segunda

Ao processar uma meta da forma


primeira clusula.

Se

clusula, que exatamente o que queremos.


No caso de

member(X, L) falhar, o corte no ser processado e Prolog tentar

a segunda clusula, que devido s variveis annimas sempre satisfeita.


Concluso: neste caso,

nonmember(X, L)

satisfeito, que tambm o que

queremos.
Este mesmo mtodo pode ser usado para implementar a negao de qualquer predicado. O uso deste artifcio to comum que existe uma notao
em Prolog para indicar esta forma de negao:

\+

antecedendo uma meta

signica a negao dela. Por exemplo, podemos denir

nonmember(X, L) :- \+ member(X, L).


Contudo, em geral estas negaes s funcionam para metas onde os argumentos vm todos instanciados.

41

5.3.3 Limitando buscas


Muitas vezes em Prolog usamos um predicado para gerar vrias alternativas que sero testadas por um segundo predicado para escolher uma delas.
Em alguns casos, o predicado gerador tem a capacidade de gerar innitas
alternativas, e o corte pode ser til para limitar esta gerao.
Considere o seguinte predicado para executar diviso inteira.

Os sistemas

Prolog em geral tm este recurso pr-denido na linguagem, atravs do operador

//,

mas usaremos esta verso mais ineciente para ilustrar o tema

desta seo.

divide(Numerador, Denominador, Resultado) :inteiro(Resultado),


Prod1 is Resultado * Denominador,
Prod2 is Prod1 + Denominador,
Prod1 =< Numerador,
Prod2 > Numerador,
!.
Esta denio usa o predicado

inteiro

denido anteriormente (pgina 38)

para gerar candidatos a quociente inteiro, que so testados pelas metas subseqentes. Note que sem o corte teramos um

loop

innito em tentativas de

ressatisfao.

5.4

Cuidados com o corte

Cortes tm um impacto signicativo no comportamento de qualquer predicado, e por isso necessrio ter clareza sobre exatamente que uso queremos
fazer de um predicado ao considerar a incluso de cortes em sua denio.
Para exemplicar esta questo, suponha que queiramos usar

member

apenas

para testar se elementos dados pertencem a listas dadas, sem nos importarmos com o nmero de vezes que aparecem. Neste caso, a denio

42

member(X, [X|_]) :- !.
member(X, [_|Y]) :- member(X, Y).
apropriada.

O predicado satisfeito uma nica vez para cada elemento

distinto da lista. Porm, perdemos a possibilidade de us-lo como gerador


de mltiplas alternativas:

?- member(X, [b, c, a]).


X = b ;
no
O caso seguinte ilustrar como o corte pode impedir que o operador de igualdade  = seja substitudo pelo uso de variveis com o mesmo nome. Considere
o predicado abaixo, que d o nmero de pais que uma pessoa tem:

pais(adao, 0).
pais(eva, 0).
pais(_, 2).
Isto , Ado e Eva tm zero pais e qualquer outra pessoa tem dois pais. Se
usarmos este predicado para descobrir quantos pais uma pessoa tem, tudo
vai bem:

?- pais(eva, N).
N = 0
?- pais(pedro, N).
N = 2
Mas quando tentamos vericar uma armao algo inesperado acontece:

?- pais(eva, 2).
yes

43

pois a meta no casa com a clusula especca para Eva, mas no h nada
para impedir que a busca continue, e acabe casando com a clusula errada.
Uma forma de arrumar isto a seguinte:

pais(adao, N) :- !, N = 0.
pais(eva, N) :- !, N = 0.
pais(_, 2).
Agora as duas primeiras clusulas vo capturar as metas envolvendo Ado
e Eva e travar ali com o corte, deixando a vericao do valor de

para o

corpo da regra.
A concluso nal que ao introduzir cortes para que o predicado sirva a
um certo tipo de metas, no h garantia que ele continuar funcionando a
contento para outros tipos de metas.

Exerccios
1. Conserte o predicato
das onde

onde ambos

fat(N, F) para que no entre em loop

en chama-

um nmero negativo e nem em chamadas vericadoras,

vm instanciados.

2. Algum teve a idia de usar

nonmember

para gerar todos os termos que

conforme denido no texto

no esto na lista

[a, b, c]

com a

pergunta

?- nonmember(X, [a, b, c]).


Vai funcionar? Por qu?
3. Suponha que algum queira listar os elementos comuns a duas listas
usando a seguinte pergunta:

?- member1(X, [a, b, a, c, a]),


member2(X, [c, a, c, a]).
Quais sero os resultados nas seguintes situaes:

44

(a)

member1

sem corte e

member2

sem corte?

(b)

member1

sem corte e

member2

com corte?

(c)

member1

com corte e

member2

sem corte?

(d)

member1

com corte e

member2

com corte?

Relembrando as denies com e sem corte:

member_com(X, [X|_]) :- !.
member_com(X, [_|Y]) :- member_com(X, Y).
member_sem(X, [X|_]).
member_sem(X, [_|Y]) :- member_sem(X, Y).

45

Captulo 6
Entrada e sada de dados

Neste captulo veremos alguns dos mecanismos que Prolog oferece para a entrada e sada de dados. Dividiremos a apresentao em trs partes: leitura e
escrita de termos; leitura e escrita de caracteres; leitura e escrita de arquivos.
Alm disso, abordaremos a questo dos operadores, que inuenciam o modo
como a leitura e a escrita ocorrem.
A descrio baseia-se no SWI Prolog. Outros sistemas podem diferir desta
implementao.

6.1

Leitura e escrita de termos

Prolog oferece o predicado pr-denido


meta

read(X)

satisfeita quando

dispositivo de entrada.

read

para a entrada de termos. A

unica com o prximo termo lido no

preciso colocar um ponto nal para sinalizar o

m do termo, sendo que este ponto nal no considerado parte do termo


lido. Unicando ou no, o termo lido consumido, ou seja, a prxima leitura
seguir da para a frente.

O termo lido pode conter variveis, que sero

tratadas como tal, mas seu escopo se restringe ao termo lido.


Se o termo lido no tiver a sintaxe de um termo em Prolog, ocorre erro de
leitura.

Se o m do arquivo for encontrado,

46

ser instanciada ao tomo

especial

end_of_file.

um erro tentar ler aps encontrar o m do arquivo.

Em caso de ressatisfao,

read

falha.

O seguinte predicado l um nmero do dispositivo de entrada e satisfeito


quando o nmero lido menor que 50.

pequeno :- read(N), N < 50.


Exemplo:

?- pequeno.
|: 40.
yes
Observe o prompt '|:' usado por Prolog para indicar que est esperando um
termo.
Para escrever termos, Prolog disponibiliza o predicado pr-denido

write,

que aceita um argumento e imprime no dispoditivo de sada o termo instanciado a este argumento. Se o argumento contm variveis no instanciadas,
estas sero impressas com seus nomes internos, geralmente consistindo de um
 _ seguido de um cdigo interno alfanumrico. Alm de
Prolog o predicado pr-denido
linha na impresso (

newline ).

linhas, devemos usar

nl,

write,

existe em

sem arugmento, que causa mudana de

Assim, se quisermos dividir a sada em vrias

nl:

?- write(pedro), nl, write(ama), nl, write(maria).


pedro
ama
maria
yes
Assim como ocorre com

read,

metas dos predicados

tisfeitas na primeira vez.

47

write,

nl

s so sa-

6.2

Leitura e escrita de caracteres

Como vimos, as constantes do tipo caractere em Prolog so denotadas usandose apstrofes, por exemplo,

'e', '\n', etc. Para a leitura de caracteres, Proget_char(X), que satisfeito unicando

log oferece o predicado pr-denido

com o prximo caractere lido do dispositivo de entrada.

possvel que

em alguns sistemas a entrada s venha a Prolog linha a linha, o que signica que at que seja teclado um ENTER o interpretador no recebe nenhum

read, o caractere lido consumido indeget_char(X) ser satisfeito ou no. O predicado get_char

caractere. Assim como acontece com


pendentemente de

falha em tentativas de ressatisfao. Se chegarmos ao m do arquivo, o tomo


especial

end_of_file

retornado.

A ttulo de exemplo, eis abaixo um predicado que l uma linha de caracteres


e informa o nmero de caracteres na linha, exceto o

newline, que indica o m

da linha. Usaremos um acumulador para contar os caracteres at o momento.

conta_linha(N) :- conta_aux(0, N).


conta_aux(A, N) :- get_char('\n'), !, A = N.
conta_aux(A, N) :- A1 is A + 1, conta_aux(A1, N).
conta_aux(A, N) satisfeito quando o nmero de caracteres a
serem lidos at o \n somado a A d N. Observe que no correto colocar um
get_char na segunda clusula de conta_aux, pois um caractere foi consumido na chamada da primeira clusula independentemente de ter sido \n ou
O predicado

no.
Para escrever caracteres, h o predicado pr-denido

put_char(X),

onde

deve ser um caractere, ou um tomo cujo nome tem apenas um caractere.


Se

estiver no instanciada ou for outro tipo de termo que no os descritos

acima, ocorre erro.

48

6.3

Ler e escrever arquivos

Os predicados de leitura que vimos at agora utilizam sempre o que chamamos de

dispositivo corrente de entrada

current_input(X)

que instancia

em Prolog.

H um predicado

ao dispositivo associado no momento

entrada de dados. Normalmente, este dispositivo o teclado, que indicado


em Prolog pelo tomo especial

user_input.

De modo semelhante, a sada de dados feita sempre atravs do

corrente de sada
instancia

em Prolog.

H um predicado

dispositivo

current_output(X)

X ao dispositivo associado sada de dados naquele momento.

que
Nor-

malmente, este dispositivo a tela do computador, que em Prolog indica-se


pelo tomo especial

user_output.

possvel trocar os dispositivos correntes de entrada e sada para arquivos,


por exemplo. Para tanto, necessrio inicialmente abrir um arquivo atravs
do predicado pr-denido

open.

Por exemplo, a pergunta

?- open('arq.txt', read, X).


vai instanciar a varivel
o arquivo

arq.txt.

X a um dispositivo de entrada que na verdade acessa

De forma semelhante, a pergunta

?- open('arq.saida', write, X).


X a um dispositivo de sada que direciona os dados para o arquivo
arq.saida. Note que o segundo argumento de open determina que tipo de
vai associar

dispositivo est sendo criado.


Aps abrir um arquivo, associando-o a um dispositivo (tambm chamado de

stream

em Prolog), pode-se us-lo como entrada ou sada atravs dos pre-

dicados pr-denidos

set_input

set_output,

que recebem um dispositivo

como argumento e tornam-no o dispositivo corrente de entrada ou sada, respectivamente. Assim, um programa em Prolog que pretenda usar um arquivo
como entrada deve proceder da seguinte forma:

programa :49

open('arq.txt', read, X),


current_input(Stream),
set_input(X),
codigo_propriamente_dito,
set_input(Stream),
close(X).
Note que foi salvo o dispositivo anterior na varivel

Stream,

para ser rees-

tabelecido como dispositivo de entrada ao trmino do programa.

Atitude

semelhante deve ser usada em relao sada.

6.4

Carregando um banco de dados

Ao escrevermos programas em Prolog, geralmente colocamos todas as clusulas dos predicados que queremos denir num arquivo, que depois carregamos
no sistema Prolog. Para carregar arquivos existe um predicado pr-denido

consult. Quando X est instanciado ao nome de um


consult(X) causa a leitura e armazenamento no banco de

em Prolog chamado
arquivo, a meta

dados de Prolog das clusulas contidas neste arquivo. Esta operao to


comum que h uma abreviatura para ela: colocar vrios nomes de arquivos
numa lista e us-la como pergunta para consult-los todos:

?- [arq1, arq2, arq3].


O predicado

consult

remove as clusulas dos predicados consultados no

banco de dados antes de carregas as novas denies.

6.5

Operadores

Como dissemos anteriormente, operadores conferem maior legibilidade, permitindo que certos funtores sejam lidos e escritos de forma prexa, inxa ou

50

prexa. Para tanto, necessrio tambm informar a precedncia e a associatividade destes operadores. Apenas funtores de aridade um ou dois podem
ser operadores.

op(Prec, Espec, Nome) para dePrec indica a precedncia, que um

Prolog oferece um predicado pr-denido


nir novos operadores. O argumento

inteiro entre 1 e 1200. Quanto mais alto este nmero, maior a precedncia.
O argumento

Espec serve para denir a aridade, a posio e a associatividade

do operador. Os seguintes tomos podem ser usados no segundo argumento:

xfx xfy yfx yfy


fx fy
xf yf
Aqui

indica a posio do operador (funtor) e

mentos.

as posies dos argu-

Na primeira linha temos portanto especicaes para operadores

binrios inxos.

Na segunda linha, especicaes para operadores unrios

prexos e na ltima linha, para operadores unrios posxos.

x e y do informaes sobre a associatividade. Numa expresso sem


x signica qualquer expresso contendo operadores de precedncia estritamente menor que a de f, enquanto y signica qualquer expresso
contendo operadores de precedncia menor ou igual a de f. Assim, em particular yfx signica que o operador associa esquerda, e xfy signica que
o operador associa direita. Se um operador declarado com xfx, ele no
As letras

parnteses,

associa.
Para exemplicar, eis a denio de alguns dos operadores em Prolog vistos
at agora.

???????-

op(1200, xfx, ':-').


op(1200, fx, '?-').
op(1000, xfy, ',').
op(900, fy, '\+').
op(700, xfx, '=').
op(700, xfx, '<').
op(700, xfx, '>').
51

????????-

op(700,
op(500,
op(500,
op(400,
op(400,
op(400,
op(400,
op(200,

xfx, 'is').
yfx, '+').
yfx, '-').
yfx, '*').
yfx, '//').
yfx, '/').
yfx, 'mod').
fy, '-').

Exerccios

1. Escreva um predicado

estrelas(N)

que imprime

caracteres  * no

dispositivo de sada.
2. Escreva um predicado
nmero

N,

N.

guess(N)

que incita o usurio a adivinhar o

O predicado repetidamente l um nmero, compara-o com

e imprime  Muito

baixo!,  Acertou!,  Muito alto!,

conforme

o caso, orientando o usurio na direo certa.


3. Escreva um predicado que l uma linha e imprime a mesma linha trocando todos os caracteres

'a'

por

52

'b'.

Captulo 7
Predicados pr-denidos

Neste captulo veremos alguns predicados pr-denidos importantes que no


foram tratados at agora. Para organizar a exposio, vamos dividi-los em
vrias partes: verdadeiros, tipos, banco de dados, listas e conjuntos, e outros.

7.1
true

Verdadeiros
satisfeito sempre, s uma vez.

repeat

satisfeito sempre, inclusive em todas as ressatisfaes.

7.2

Tipos

var(X)

satisfeito quando

novar(X)

uma varivel no instanciada.

satisfeito quando

contrrio de

atom(X)

var(X).

satisfeito quando

um termo ou uma varivel instanciada. O

um tomo (constante no numrica).

number(X)

satisfeito quando

um nmero.

atomic(X)

satisfeito quando

um tomo ou um nmero.

53

7.3

Banco de dados

listing

satisfeito uma vez, e lista todas as clusulas do banco de dados.

listing(P)

satisfeito uma vez, e lista todas as clusulas do predicado

P.

asserta(X), assertz(X) so satisfeitos uma vez, e adicionam a clusula


X ao banco de dados. O predicado asserta adiciona a clusula nova
antes das outras do mesmo predicado. O predicado assertz adiciona
a clusula nova

retract(X)

7.4

depois das outras do mesmo predicado.

satisfeito uma vez, e remove a clusula

do banco de dados.

Listas

last(X, L)

satisfeito quando

reverse(L, M)

o ltimo elemento da lista

satisfeito quando a lista

delete(X, L, M)

satisfeito quando a lista

o de todas as ocorrncias de

7.5

em

L.

L.

a reversa da lista

M.

M obtida da lista L pela remo-

Conjuntos (listas sem repeties)

subset(X, Y)

satisfeito quando

elementos de

esto em

Y.

um subconjunto de

intersection(X, Y, Z) satisfeito quando a


mentos comuns a X e a Y, e apenas estes.

lista

Y,

isto , todos os

contm todos os ele-

union(X, Y, Z) satisfeito quando a lista Z contm todos os elementos que


esto em X ou em Y, e apenas estes.

54

7.6

Outros

X =.. L

satisfeito se

X um termo e L uma lista onde aparecem o funtor


X na ordem. Exemplos:

e os argumentos de

?- gosta(maria, pedro) =.. L.


L = [gosta, maria, pedro]
?- X =.. [a, b, c, d].
X = a(b, c, d)
random(N)

em SWI Prolog um operador que pode ser usado em uma ex-

is, e produz um inteiro


X is random(30000).

presso aritmtica direita de


intervalo 0 a

N-1.

findall(X, M, L)

Exemplo:

aleatrio no

L a uma lista contendo todos os objetos X para


os quais a meta M satisfeita. O argumento M um termo que ser usado
como meta. A varivel X deve aparecer em M. Exemplo: findall(X,
member(X,[a,b,c]), L) far com que L seja instanciada com a prpria
lista [a,b,c].

instancia

um operador binrio que signica ou. satisfeito quando uma das duas
metas satisfeita. Em geral, pode ser substitudo por duas clusulas.
Por exemplo,

atomic(X) :- (atom(X) ; number(X)).


equivalente a

atomic(X) :- atom(X).
atomic(X) :- number(X).

55

Captulo 8
Estilo e depurao

A melhor maneira de evitar ou minimizar erros programar com cuidado,


seguindo as regras de estilo, consagradas ao longo de vrias dcadas pelos
melhores programamdores. O provrbio  melhor prevenir do que remediar
aplica-se muito bem neste cenrio.

Seguem-se algumas recomendaes de

estilo ao escrever programas em Prolog.

Coloque em linhas consecutivas as clusulas de um mesmo predicado, e


separe cada predicado do prximo com uma ou mais linhas em branco.

Se uma clusula cabe toda dentro de uma linha (at cerca de 70 caracteres), deixe-a em uma linha. Caso contrrio, coloque apenas a cabea
e o  :- na primeira linha, e, nas linhas subseqentes, coloque as submetas do corpo, indentadas com TAB e terminadas por vrgula, exceto
a ltima, que terminada com ponto nal.

Evite predicados com muitas regras.

Se um predicado tem mais de

cinco ou dez regras, considere a possibilidade de quebr-lo em vrios


outros predicados.

Evite o uso de  ;, substituindo-o por mais de uma clusula quando


possvel.

Use variveis annimas para variveis que ocorrem apenas uma vez
numa clusula.

56

Ao lado destas recomendaes gerais, bom estar atento aos seguintes cuidados ao denir um predicado:

Verique se seu nome est digitado corretamente em todas as ocorrncias. Erros de digitao so comuns.

Verique o nmero de argumentos e certique-se de que combina com


o seu projeto para este predicado.

Identique todos os operadores usados e determine sua precedncia,


associatividade e argumentos para vericar se esto de acordo com o
planejado. Em caso de dvidas, use parnteses.

Observe o escopo de cada varivel. Observe quais variveis vo compartilhar o mesmo valor quando uma delas car instanciada. Observe
se todas as variveis da cabea de uma regra aparecem no corpo da
regra.

Tente determinar quais argumentos devem vir instanciados ou no instanciados em cada clusula.

Identique as clusulas que representam condies de parada. Verique


se todas as condies de parada esto contempladas.

Fique atento tambm para certos erros comuns que costumam assolar os
programas feitos s pressas:

No esquea o ponto nal ao temino de cada clusula.


arquivo, certique-se de que haja um

newline

No nal do

aps o ltimo ponto

nal.

Verique o casamento dos parnteses e colchetes. Um bom editor (por


exemplo, Emacs) pode ajudar nesta tarefa.

Cuidado com erros tipogrcos nos nomes de predicados pr-denidos.


Tenha sempre mo (ou Web) um manual completo da implementao de Prolog que voc est usando. Consulte-o para certicar-se do
uso correto dos predicados pr-denidos em seu programa.

57

8.1

Depurao

Programas feitos com cuidado tendem a apresentar menos erros, mas difcil
garantir que no haver erros. Caso seu programa no esteja funcionando,
ou seja, provocando erros de execuo, dando a resposta errada ou simplesmente respondendo  no, voc pode usar os potentes recursos de depurao
de Prolog para localizar e corrigir os erros. H predicados pr-denidos para
ajud-lo nesta tarefa. Nesta seo descreveremos os predicados de depurao
existentes na implementao SWI Prolog. Outras implementaes podem ter
predicados ligeiramente diferentes para depurao.
O predicado

trace,

sem argumentos, liga o mecanismo de acompanhamento

de metas. Cada meta impressa nos seguintes eventos:

CALL quando ocorre uma tentativa de satisfao da meta


EXIT quando a meta satisfeita
REDO quando ocorre uma tentativa de ressatisfao da meta
FAIL quando a meta falha

trace, h o predicado notrace. O predicado spy(P)


P, ou seja, faz com que os eventos relacionados s metas do predicado
P sejam acompanhados. Para cancelar este efeito, use nospy(P). O predicado
debugging, sem arugmentos, indica o status da depurao e lista todos os
Para cancelar o efeito de

espia

predicados que esto sob espionagem.


Quando o acompanhamento de metas est ligado, Prolog pra a execuo
em cada evento relevante e nos mostra o evento e a meta que est sendo
examinada. Neste ponto temos controle sobre como continuar o acompanhamento, com vrias opes. As opes so escolhidas por teclas, geralmente
a primeira letra de um verbo em ingls que nos lembra a ao a realizar. A
Tabela 8.1 contm algumas das opes disponveis.

58

Opo

Verbo

Descrio

write

imprime a meta

creep

segue para o prximo evento

skip

salta at o prximo evento desta meta

leap

salta at o prximo evento acompanhado

retry

volta primeira satisfao da meta

fail

break

inicia uma sesso recursiva do interpretador

abort

interrompe a depurao

causa a falha da meta

Tabela 8.1: Possveis aes numa parada de depurao.

59

Captulo 9
Gramticas

Um dos principais usos de Prolog em processamento de linguagens naturais.


Seu emprego to intenso nesta rea que Prolog oferece mecanismos especcos para tratar este problema.

Nesta seo conheceremos alguns destes

mecanismos.

9.1

O problema da anlise lxica

Para enteder uma frase numa lngua qualquer, o primeiro passo geralmente
consiste em vericar se a frase segue as regras gramaticais da lngua. Computacionalmente, uma das maneiras mais simples de fazer esta vericao
usando gramticas livres de contexto, como a que especicamos abaixo:

sentenca > sujeito, predicado.


sujeito > artigo, substantivo.
predicado > verbo.
predicado > verbo, objeto.
artigo > [o].
artigo > [a].
60

substantivo > [pera].


substantivo > [homem].
verbo > [come].
verbo > [canta].
objeto > artigo, substantivo.
A gramtica consiste em um certo nmero de regras, que dizem como os
diversos tens da frase podem ser decompostos. Por exemplo, as regras acima
denem que uma sentena vlida deve ser composta de um sujeito seguido
de um predicado. Por sua vez, um sujeito formado por um artigo seguido
de um substantivo. E assim por diante.
Desta forma, para vericar se uma sentena vlida, devemos tentar encaixla na denio acima. Tome como exemplo a frase o homem come a pera.
Ela pode ser encaixada na gramtica que demos da maneira indicada na
Figura 9.1

sentenca

sujeito

homem

predicado

verbo

objeto

come

pera

Figura 9.1: Anlise lxica da sentena o homem come a pera.

61

Ao denir os diversos itens da frase, h sempre um que o principal, do qual


emanam todos os demais.

No nosso caso, este item sentenca, denido

na primeira regra. E, ao denir cada item em funo de outros, fatalmente


acabamos chegando aos itens chamados terminais, para os quais a denio
dada em termos de exemplos concretos. Os itens verbo, artigo e susbtantivo
so terminais na gramtica dada anteriormente. Observe que indicamos isto
usando uma notao de lista para os exemplos.
Pois bem, o problema da anlise lxica e dada uma frase qualquer, determinar
se ela se encaixa numa descrio de gramtica cmo a que demos nesta seo, e
construir uma rvore lxica para ela, nos moldes da Figura 9.1. Um programa
que faa isto chamado de analisador lxico.
A formalizao de regras sintticas que ilustramos nesta seo chamada de
DCG, sigla do ingls

Denite Clause Grammar.

Muitas implementaes Pro-

log fornecem mecanismos para lidar com estas gramticas e executar anlise
lxica, complementada por vrias funcionalidades extras, como veremos no
restante deste captulo.

9.2

Anlise lxica em Prolog

Ao realizar anlise lxica em Prolog, usual representar palavras por tomos


e frases por listas de tomos. Assim, a frase o homem come a pera seria
representada pela lista

[o, homem, come, a, pera]


Isto posto, natural implementar a anlise lxica como um predicado que ser
satisfeito quando a frase dada (em forma de lista) segue as regras gramaticais

sentenca(X)
X for uma lista de palavras que formam uma sentena

indicadas, e falha caso contrrio. Assim, teremos um predicado


que satisfeito quando
vlida.
Como testar isto?

Bem, segundo as regras, uma sentena vlida deve ser

formada por um sujeito seguido de um predicado. Observe que a predicado

62

est agora sendo umada em dois sentidos diferentes. Um deles so os predicados em Prolog. O outro o predicado que um item, ou seja, uma parte,
de uma frase vlida. Cuidado para no confundir estes dois usos!
Continuando, seria interessante ter predicados (de Prolog) para validar os

sujeito(X) que satisfeito quando X representa um sujeito vlido, e predicado(X) que satisfeito
quando X representa um predicado vlido. Com isto, poderamos escrever o
predicado sentenca em funo de outros, como segue:
outros itens da frase, por exemplo, um predicado

sentenca(X) :append(Y, Z, X), sujeito(Y), predicado(Z).


Note o uso de

append, que quebra a frase inicial de todas as formas possveis

e testa, para cama uma delas, se os pedaos resultantes podem ser vistos
como sujeitos e predicados. Para que o predicado

sentenca possa funcionar,

preciso denir todos os outros dos quais depende. A denio nal caria
algo como:

sentenca(X) :append(Y, Z, X), sujeito(Y), predicado(Z).


sujeito(X) :append(Y, Z, X), artigo(Y), substantivo(Z).
predicado(X) :- verbo(X).
predicado(X) :append(Y, Z, X), verbo(Y), objeto(Z).
artigo([o]).
artigo([a]).
substantivo([pera]).
substantivo([homem]).
verbo([come]).
verbo([canta]).
63

objeto(X) :append(Y, Z, X), artigo(Y), substantivo(Z).


Observe que, para os itens terminais, as denies se transformam em fatos
Prolog e no em regras Prolog.

Note tambm que denies alternativas

naturalmente se transformam em clusulas alternativas em Prolog.


Agora o programa est completo, e ser capaz de vericar frases de acordo
com a nossa gramtica. A pergunta

?- sentenca([o, homem, come, a, pera]).


yes
respondida corretamente. Tambm frases gramaticalmente incorretas como

?- sentenca([homem, pera, come, a, o]).


no
so classicadas como tais.
Apesar de correto, o esquema acima no o mais eciente possvel, pois

append

experimenta todas as combinaes de quebra da frase, sendo que

em geral apenas uma ou duas delas sero corretas. O mesmo acontece nos
pedaos de frases passados aos predicados de todos os intens tornando a
busca ineciente.
Mas, como melhorar a performance?

A resposta est nos acumuladores,

que estudamos na Seo 4.5. Comeamos por fazer com que o predicado de
cada item tenha no um mas

dois parmetros, com o seguinte signicado,

exemplicado abaixo para o predicado

sujeito(X, Y)

sujeito:

satisfeito quando

X
Y.

existe um sujeito no incio da lista


e o resto da lista aps o sujeito

64

Para ajudar a entender o conceito, damos a seguir algumas perguntas que


seriam respondidas armativamente com esta nova interpretao:

????-

sujeito([o,
sujeito([a,
sujeito([o,
sujeito([a,

homem, come, a pera], [come, a, pera]).


pera, canta], [canta]).
homem, come, a pera], X).
pera, canta], X).

sendo que, nas duas ltimas, a varivel

ca instanciada com o que sobrar

da lista aps um sujeito.


Precisamos tambm modicar as denies dos predicados para acomodar o
novo signicado. Por incrvel que parea, as denies cam mais simples, e
evitam o uso de

append.

Tomando como exemplo o caso de

sujeito, camos

com:

sujeito(X, Y) :- artigo(X, Z), substantivo(Z, Y).


X deixando uma cauda igual a Y se
X deixando uma cauda Z, e no incio desta cauda
Z existe um substantivo, deixando uma cauda Y. A Figura 9.2 mostra o que
seriam os pedaos X, Y e Z num caso prtico.

Ou seja, existe um sujeito no incio de


existe um artigo no incio de

homem

come

pera

Y
Z
X
Figura 9.2: Valor dos parmetros

X, Y e Z numa anlise lxica para sujeito.

Note, porm, que a nova denio de


sula da denio de

append.

sujeito lembra muito a segunda clu-

como se a tivessemos incorporado em cada

item. Vejamos como ca o programa inteiro.

65

sentenca(S0, S) :- sujeito(S0, S1), predicado(S1, S).


sujeito(S0, S) :- artigo(S0, S1), substantivo(S1, S).
predicado(S0, S) :- verbo(S0, S).
predicado(S0, S) :- verbo(S0, S1), objeto(S1, S).
artigo([o|S], S).
artigo([a|S], S).
substantivo([pera|S], S).
substantivo([homem|S], S).
verbo([come|S], S).
verbo([canta|S], S).
objeto(S0, S) :- artigo(S0, S1), substantivo(S1, S).
Observe como a nova denio se reete nos itens terminais. Eles tambm
tm dois parmetros, sendo o primeiro a entrada e o segundo, o resto aps o
terminal. No caso dos terminais, onde temos tomos concretos para o item,
o segundo parmetro simplesmente a cauda do primeiro, aps consumido
o tomo em questo.
Estas novas denies tornam o programa mais eciente, mantendo-o correto.

Porm, ainda d pra melhorar a forma, simplicando o trabalho do

programador, como veremos na prxima seo.

9.3

Notao para regras gramaticais

SWI-Prolog, assim como vrias outras implementaes, oferece uma maneira


mais conveniente de escever gramticas livres de contexto. Basicamente, tudo
o que temos que fazer descrever a gramtica exatamente como foi feito no
incio deste captulo, usando o funtor

> para indicar as regras gramaticais.

Prolog sabe traduzir esta notao em clusulas da maneira mais eciente

66

explicada na Seo 9.2, gerando um predicado de dois parmteros para cada


item.
Para test-lo, pode-se usar perguntas como as seguintes:

?- sentenca([o, homem, come, a, pera], [ ]).


yes
?- sujeito([o, homem, canta], X).
X = [canta]

9.4

Argumentos adicionais

Alm dos dois argumentos que a notao para regras gramaticais automaticamente cria, possvel acrescentar argumentos adicionais para propsitos
especcos. Vamos trabalhar um exemplo onde esta funcionalidade pode ser
til. Trata-se da concordncia em nmero entre sujeito e verbo. Sentenas
como os homens come a pera ou ento o homem comem a pera no so
corretas, mas seriam aceitas pela extenso natural de nossa gramtica inicial
ao incluir o artigo os, o substantivo homens e o verbo comem, ou seja,
as formas plurais de itens terminais j presentes na gramtica.
Para conseguir a concordncia em nmero entre o sujeito e o predicado,
criaremos um argumento adicional para indicar se a frase est no singular
ou no plural. Este argumento ser passado a todos os itens, e servir para
garantir que sujeitos no singular combinem-se apenas com predicados no
plural para constituir frases corretas. A gramtica modicada car assim:

sentenca > sentenca(X).


sentenca(X) > sujeito(X), predicado(X).
sujeito(X) > artigo(X), substantivo(X).
predicado(X) > verbo(X).
predicado(X) > verbo(X), objeto(_).
67

artigo(singular) > [o].


artigo(singular) > [a].
artigo(plural) > [os].
artigo(plural) > [as].
substantivo(singular) > [pera].
substantivo(singular) > [homem].
substantivo(plural) > [peras].
substantivo(plural) > [homens].
verbo(singular) > [come].
verbo(singular) > [canta].
verbo(plural) > [comem].
verbo(plural) > [cantam].
objeto(X) > artigo(X), substantivo(X).
Note que as regras continuam essencialmente as mesmas, apenas com o argumento adicional indicando se a frase est no singular ou no plural. Nos
itens terminais, foi necessrio acrescentar fatos adicionais com as verses dos
itens no prural. Agora nossas regras so capazes de vericar a concordncia
em nmero:

?- sentenca(X, [os, homens, comem, as, peras], [ ]).


X = plural
?- sentenca(X, [o, homens, come, as, pera], [ ]).
no
Observe ainda que, na segunda clusula para predicado, a concordncia se d
entre predicado e verbo, mas o objeto no precisa concordar com este verbo,
visto que ele est ligado ao sujeito. Assim, frases como

?- sentenca(X, [o, homem, come, as, peras], [ ]).


X = singular
so tambm corretamente aceitas e classicadas.

68

Bibliograa

[1] William F. Clocksin and Christopher S. Mellish.

using the ISO standard.

Programming in Prolog:

Springer-Verlag, 5a. edition, 2003. ISBN 3-540-

00678-8.

69

Você também pode gostar