Você está na página 1de 70

MC336 - Paradigmas de programao

Prolog

Joo Meidanis


c Copyright 2011 J. Meidanis
Contedo

1 Introduo 4

1.1 Objetos e relaes . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Programao em Prolog . . . . . . . . . . . . . . . . . . . . . 5

1.3 Fatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.4 Perguntas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.5 Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

1.6 Conjunes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.7 Regras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Sintaxe e unicao 15

2.1 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.2 Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.3 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.4 Igualdade e unicao . . . . . . . . . . . . . . . . . . . . . . 18

3 Aritmtica 20

1
4 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

5 Backtracking e o corte 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

5.4 Cuidados com o corte . . . . . . . . . . . . . . . . . . . . . . . 42

6 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

2
7 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

8 Estilo e depurao 56

8.1 Depurao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

9 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

3
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, Program-


ming in Prolog [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 e 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.

4
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 proporci-
ona 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). Pedro gosta de Maria


gosta(maria, pedro). Maria gosta de Pedro
valioso(ouro). Ouro valioso
mulher(jane). Jane mulher
possui(jane, ouro). Jane possui ouro
pai(pedro, maria). Pedro pai de Maria
entrega(romeu, livro, maria). Romeu entrega o livro a Maria

5
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


Terminologia: relaes so
argumentos. Chamaremos de banco de dados coleo de fatos e regras que
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 provar
o fato a partir de seu banco de dados. Conra isto no seguinte exemplo.
Considere o banco de dados:

humano(socrates).
humano(aristoteles).
ateniense(socrates).

e a pergunta:

6
?- 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. Nova-
mente, 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 X 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 unica-
o foi feita.

7
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 flores, ento Prolog respondeu
X = flores. 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
ponto-e-vrgula (;) seguindo de ENTER, Prolog vai continuar sua busca do
ponto onde tinha parado, tentando encontrar uma outra resposta pergunta.
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). pergunta inicial


X = maria ; primeira resposta
no no h mais respostas

1.6 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 e 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 ilustra-
tivo do que chamamos de backtracking pois os seguintes eventos ocorrem:

1. a primeira meta encontra o fato unicador gosta(maria, chocolate).


A varivel X instanciada a chocolate em todas as ocorrncias de X
na pergunta. Prolog marca esta posio para a primeira meta e a
instanciao de X.
2. a segunda meta, que virou gosta(pedro, chocolate) devido instan-
ciao de 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 X a vinho.
4. Prolog tenta a prxima meta, que agora gosta(pedro, vinho). Esta
no uma ressatisfao, mas sim uma meta inteiramente nova, e por-
tanto 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. A este processo se d o nome de
backtracking.

1.7 Regras

Uma 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 X se X 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.

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


que est sendo denido. O corpo, no caso gosta(X, vinho), uma conjun-
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 X ocorre trs vezes na regra. Dizemos que o
escopo de X a regra toda. Isto signica que quando X for instanciada, as
trs ocorrncias tero o mesmo valor.

A maneira como as regras funcionam em relao satisfao de metas


a seguinte. Uma meta unica com uma regra se ela unica com a cabea
da regra. 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 pais com trs argumentos

11
tal que pais(X, Y, Z) signica que os pais de X so Y e Z. O segundo
argumento a me e o terceiro o pai de X. Usaremos tambm os predicados
mulher e homem para indicar o sexo das pessoas.

homem(alberto).
homem(eduardo).

mulher(alice).
mulher(vitoria).

pais(eduardo, vitoria, alberto).


pais(alice, vitoria, alberto).

Deniremos agora o predicado irma_de tal que irma_de(X, Y) seja satisfeito


quando X for irm de Y. Dizemos que X irm de Y quando:

X mulher

X tem me M e pai P, e

Y tem os mesmos pais de 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 Ta-


bela 1.1, onde numeramos as variveis com ndices de acordo com a meta,

12
Tabela 1.1: Processamento da meta irma_de(alice, eduardo).

N Meta Marca Variveis


1 irma_de(alice,eduardo) irma_de, X1 = alice,
regra 1 Y1 = eduardo
2 mulher(alice) mulher, -
fato 1
3 pais(alice,M1 ,P1 ) pais, M1 = vitoria,
fato 2 P1 = alberto
4 pais(eduardo,vitoria,alberto) pais, -
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: sim. Suponha
agora que queiramos saber de quem 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).

N Meta Marca Variveis


1 irma_de(alice,X) irma_de, X1 = alice,
regra 1 Y1 = X
2 mulher(alice) mulher, -
fato 1
3 pais(alice,M1 ,P1 ) pais, M1 = vitoria,
fato 2 P1 = alberto
4 pais(Y1 ,vitoria,alberto) pais, Y1 = eduardo
fato 1

Exerccios

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


exemplo envolvendo o predicado irma_de acima. Este o compor-
tamento esperado? Como consertar a regra, supondo que existe um
predicado dif(X,Y) que satisfeito quando X e Y so diferentes?

14
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 constante, uma varivel, ou uma estrutura.

2.1 Constantes

As 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 indica um objeto ou uma relao. Nomes de objetos como maria,


livro, 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 ( underscore )  _. Estas ltimas so
chamadas de variveis annimas.
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

As estruturas so termos mais complexos formados por um funtor seguido de


componentes separadas por vrgula e colocadas entre parnteses. 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 aridade. Funtores de aridade


igual a zero so na verdade as constantes. 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 pre-
xa, 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 +, -, *, / tm geralmente posio


inxa. O operador unrio de negao em geral prexo, e o operador de
fatorial (!) em geral posxo. A precedncia de * e / maior que de + e
-. A associatividade de todos os operadores aritmticos esquerda, o que
signica que uma expresso como 8/2/2 ser interpretada como (8/2)/2 e
no 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 pr-


denido = 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 unica-


o, 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, vari-
vel, 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 varivel estrutura
constante s se for a sempre; causa nunca
mesma instanciao
varivel sempre; causa tornam-se liga- sempre; causa
instanciao das instanciao
T1
estrutura nunca sempre; causa mesmo funtor,
instanciao mesmo nmero
de componen-
tes e cada com-
ponente igual

Tabela 2.1: Condies para que dois termos se uniquem, segundo seus sub-
tipos. O subtipo varivel signica varivel no instanciada. O subtipo
estrutura signica estruturas com aridade maior ou igual a um.

18
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 compara-
o.

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 <= como na


maioria das linguagens. Isto foi feito para liberar o predicado <=, 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 ex-
presso, 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 representar a populao
de um pas em milhes de pessoas, e o predicado 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:

+ soma
- subtrao
* multiplicao
/ diviso
// diviso inteira
mod 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 is 2 + 3.
?- X is Y + Z.
?- 6 is 2 * 4.
?- X = 5, Y is X // 2.
?- Y is X // 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 estru-
turas 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 es-


trutura com palavras da sentena, camos com o resultado mostrado na
Figura 4.2.

sentenca sentenca

sujeito predicado sujeito predicado

X verbo objeto pedro verbo objeto

Y Z 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. Por exemplo, a
estrutura f(X, g(X, 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
f

X a

Figura 4.3: Diagrama mostrando ocorrncias da mesma varivel.

Em Prolog, Uma lista :

ou uma lista vazia, escrita como [ ],


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. Na
Figura 4.4 vemos uma lista que seria escrita como .(a, .(b, .(c, [ ]))),
em Prolog. Em LISP, esta mesma lista seria representada como (a . (b .
(c . ()))).

. . . []

a b c

Figura 4.4: Uma lista em Prolog.

A exemplo de LISP, Prolog tambm tem uma maneira alternativa, mais pr-
tica, 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 .(X, Y) usando a barra
vertical  |: [X|Y]. 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 entre objetos e listas onde eles aparecem. Escreve-
remos um predicado member tal que member(X, Y) verdadeiro quando o

28
termo X um elemento da lista Y. H duas condies a vericar. Em pri-
meiro lugar, um fato que X membro de Y se X for igual cabea de Y, o
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.

A segunda (e ltima) regra diz que X membro de Y se X membro da cauda


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

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 Z por Y, j que Y 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 condies de
parada e para o caso recursivo. No caso de member, 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).

Prolog estrar em loop at esgotar a memria. O predicado homem est


denido usando recurso esquerda, ou seja, a chamada recursiva a meta mais
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 di-


minuindo, 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. Estes
argumentos recebem o nome de acumuladores.
No prximo exemplo mostraremos uma denio para o predicado listlen
sem acumulador e depois com acumulador. A meta listlen(L, N) satis-
feita quando o comprimento da lista L igual a N. Prolog possui o predicado
pr-denido length 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 de-
nio funcione. A denio com acumulador baseia-se no mesmo princpio
recursivo, mas acumula a resposta a cada passo num argumento extra. Usa-
mos um predicado auxiliar lenacc que uma generalizao de listlen. A
meta 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:

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 N so variveis distintas mas ligadas entre si no procesamento


das regras denidas. Esta ltima meta unica com a condio de parada (a
primeira clusula de lenacc) e instancia N como 5, o que faz com que o N de
listlen seja tambm igual a 5.

Acumuladores no precisam ser nmeros inteiros. Considere a seguinte de-


nio 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).

O segundo argumento de revacc serve como acumulador. Observe a seqn-


cia de metas usadas para responder pergunta ?- rev([a, b, c, d], L3).:

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)

Nestas metas todas as variveis L3 so distintas mas ligadas. Os elementos


vo saindo de L1 e entrando em L2 a cada chamada. Os elementos saem e
entram pela frente nas listas, combinando com as operaes de lista em Prolog
que s permitem manipular diretamente a cabea. No nal, a clusula de
parada instancia L3 reversa.

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


nicado dos predicados a denir. Neste exemplo, essencial entender o

34
que signica o predicado revacc: a meta revacc(L1, L2, L3) satisfeita
quando a reversa da lista L1 concatenada com a lista L2 resulta em L3. De
posse desta denio em palavras mais fcil chegar denio em Prolog.

Exerccios

1. Escreva um predicado last(L, X) que satisfeito quando o termo X


o ltimo elemento da lista L.

2. Escreva um predicado efface(L1, X, L2) que satisfeito quando L2


a lista obtida pela remoo da primeira ocorrncia de X em L1.
3. Escreva um predicado delete(L1, X, L2) que satisfeito quando L2
a lista obtida pela remoo de todas as ocorrncias de X em L1.

35
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 k 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 k.1, k.2, etc. A satisfao
de k 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), junta-
mente 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 uni-


cao 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 com mais detalhe


e conhecer o corte, um mecanismo especial que inibe o backtracking em
certas condies.

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


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, jorge).
pai(pedro, jorge).
pai(sueli, haroldo).
pai(jorge, 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 = jorge ;
X = jorge ;
X = haroldo ;
X = eduardo ;
no

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 al-


ternativas 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 argu-


mentos. 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. Se o corte a meta k.l, sua meta me a meta
k . Numa tentativa de ressatisfao do corte, ele causa a falha da meta
k como um todo, e o backtracking continua tentando ressatisfazer a meta
anterior a k .

Vejamos um exemplo. Considere a regra

g :- a, b, c, !, d, e, f.

Prolog realiza o backtracking normalmente entre as metas a, b e c at que o


sucesso de c cause a satisfao do corte e Prolog passe para a meta d. O
processo de backtracking acontece normalmente entre d, e e f, mas se d em
algum momento falhar, o que ocorre que a meta envolvendo g que casou
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
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  out of memory )

A denio de fat 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 fail
que sempre falha. 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.

Suponha que precisemos de um predicado 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
usando corte e falha:

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


nonmember(_, _).

Ao processar uma meta da forma nonmember(X, L), Prolog vai tentar a


primeira clusula. Se 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
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 qual-
quer 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 argu-


mentos vm todos instanciados.

41
5.3.3 Limitando buscas
Muitas vezes em Prolog usamos um predicado para gerar vrias alternati-
vas 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 ope-
rador //, 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 sub-
seqentes. 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 predi-


cado, 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 importar-
mos 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 igual-
dade  = 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 N 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 fat(N, F) para que no entre em loop en chama-


das onde N um nmero negativo e nem em chamadas vericadoras,
onde ambos N e F vm instanciados.

2. Algum teve a idia de usar nonmember conforme denido no texto


para gerar todos os termos que 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 en-
trada 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 read para a entrada de termos. A


meta read(X) satisfeita quando X unica com o prximo termo lido no
dispositivo de entrada. 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, X ser instanciada ao tomo

46
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 instan-
ciado 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 write, existe em
Prolog o predicado pr-denido nl, sem arugmento, que causa mudana de
linha na impresso ( newline ). Assim, se quisermos dividir a sada em vrias
linhas, devemos usar nl:

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


pedro
ama
maria

yes

Assim como ocorre com read, metas dos predicados write, e nl s so sa-
tisfeitas na primeira vez.

47
6.2 Leitura e escrita de caracteres

Como vimos, as constantes do tipo caractere em Prolog so denotadas usando-


se apstrofes, por exemplo, 'e', '\n', etc. Para a leitura de caracteres, Pro-
log oferece o predicado pr-denido get_char(X), que satisfeito unicando
X 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 signi-
ca que at que seja teclado um ENTER o interpretador no recebe nenhum
caractere. Assim como acontece com read, o caractere lido consumido inde-
pendentemente de get_char(X) ser satisfeito ou no. O predicado get_char
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).

O predicado 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 consu-
mido na chamada da primeira clusula independentemente de ter sido \n ou
no.

Para escrever caracteres, h o predicado pr-denido put_char(X), onde X


deve ser um caractere, ou um tomo cujo nome tem apenas um caractere.
Se X 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 cha-


mamos de dispositivo corrente de entrada em Prolog. H um predicado
current_input(X) que instancia X 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 dispositivo


corrente de sada em Prolog. H um predicado current_output(X) que
instancia X ao dispositivo associado sada de dados naquele momento. 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 X a um dispositivo de entrada que na verdade acessa


o arquivo arq.txt. De forma semelhante, a pergunta

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

X a um dispositivo de sada que direciona os dados para o arquivo


vai associar
arq.saida. Note que o segundo argumento de open determina que tipo de
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 e set_output, que recebem um dispositivo
como argumento e tornam-no o dispositivo corrente de entrada ou sada, res-
pectivamente. 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 clusu-


las dos predicados que queremos denir num arquivo, que depois carregamos
no sistema Prolog. Para carregar arquivos existe um predicado pr-denido
em Prolog chamado consult. Quando X est instanciado ao nome de um
arquivo, a meta consult(X) causa a leitura e armazenamento no banco de
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, per-


mitindo que certos funtores sejam lidos e escritos de forma prexa, inxa ou

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

Prolog oferece um predicado pr-denido op(Prec, Espec, Nome) para de-


nir novos operadores. O argumento Prec indica a precedncia, que um
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 f indica a posio do operador (funtor) e x e y as posies dos argu-


mentos. 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.

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


parnteses, x signica qualquer expresso contendo operadores de precedn-
cia estritamente menor que a de f, enquanto y signica qualquer expresso
contendo operadores de precedncia menor ou igual a de f. Assim, em par-
ticular yfx signica que o operador associa esquerda, e xfy signica que
o operador associa direita. Se um operador declarado com xfx, ele no
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, xfx, 'is').
?- op(500, yfx, '+').
?- op(500, yfx, '-').
?- op(400, yfx, '*').
?- op(400, yfx, '//').
?- op(400, yfx, '/').
?- op(400, yfx, 'mod').
?- op(200, fy, '-').

Exerccios

1. Escreva um predicado estrelas(N) que imprime N caracteres  * no


dispositivo de sada.

2. Escreva um predicado guess(N) que incita o usurio a adivinhar o


nmero N. O predicado repetidamente l um nmero, compara-o com
N, 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 tro-


cando todos os caracteres 'a' por 'b'.

52
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 Verdadeiros

true satisfeito sempre, s uma vez.

repeat satisfeito sempre, inclusive em todas as ressatisfaes.

7.2 Tipos

var(X) satisfeito quando X uma varivel no instanciada.

novar(X) satisfeito quando X um termo ou uma varivel instanciada. O


contrrio de var(X).
atom(X) satisfeito quando X um tomo (constante no numrica).

number(X) satisfeito quando X um nmero.

atomic(X) satisfeito quando X 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 depois das outras do mesmo predicado.

retract(X) satisfeito uma vez, e remove a clusula X do banco de dados.

7.4 Listas

last(X, L) satisfeito quando X o ltimo elemento da lista L.


reverse(L, M) satisfeito quando a lista L a reversa da lista M.
delete(X, L, M) satisfeito quando a lista M obtida da lista L pela remo-
o de todas as ocorrncias de X em L.

7.5 Conjuntos (listas sem repeties)

subset(X, Y) satisfeito quando X um subconjunto de Y, isto , todos os


elementos de X esto em Y.
intersection(X, Y, Z) satisfeito quando a lista Z contm todos os ele-
mentos comuns a X e a Y, e apenas estes.

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


e os argumentos de X na ordem. Exemplos:
?- 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-
presso aritmtica direita de is, e produz um inteiro aleatrio no
intervalo 0 a N-1. Exemplo: X is random(30000).
findall(X, M, L) instanciaL 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].

; 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 carac-
teres), deixe-a em uma linha. Caso contrrio, coloque apenas a cabea
e o  :- na primeira linha, e, nas linhas subseqentes, coloque as sub-
metas 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 cui-
dados ao denir um predicado:

Verique se seu nome est digitado corretamente em todas as ocorrn-


cias. 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 com-


partilhar 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 ins-


tanciados 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. No nal do


arquivo, certique-se de que haja um newline 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 implemen-
tao 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 simples-
mente 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

Para cancelar o efeito detrace, h o predicado notrace. O predicado spy(P)


espiaP, 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
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 acompanha-
mento, 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
w write imprime a meta
c creep segue para o prximo evento
s skip salta at o prximo evento desta meta
l leap salta at o prximo evento acompanhado
r retry volta primeira satisfao da meta
f fail causa a falha da meta
b break inicia uma sesso recursiva do interpretador
a abort interrompe a depurao

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 espe-
ccos 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. Com-
putacionalmente, 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 encaix-
la 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 predicado

o homem verbo objeto

come a 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
indicadas, e falha caso contrrio. Assim, teremos um predicado sentenca(X)
que satisfeito quando X for uma lista de palavras que formam uma sentena
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 predi-
cados 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


outros itens da frase, por exemplo, um predicado sujeito(X) que satis-
feito 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:

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:

sujeito(X, Y) satisfeito quando


existe um sujeito no incio da lista X
e o resto da lista aps o sujeito Y.

64
Para ajudar a entender o conceito, damos a seguir algumas perguntas que
seriam respondidas armativamente com esta nova interpretao:

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


?- sujeito([a, pera, canta], [canta]).
?- sujeito([o, homem, come, a pera], X).
?- sujeito([a, pera, canta], X).

sendo que, nas duas ltimas, a varivel X 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).

Ou seja, existe um sujeito no incio deX deixando uma cauda igual a Y se


X deixando uma cauda Z, e no incio desta cauda
existe um artigo no incio de
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.

o homem come a pera


Y

Figura 9.2: Valor dos parmetros X, Y e Z numa anlise lxica para sujeito.

Note, porm, que a nova denio de sujeito lembra muito a segunda clu-
sula da denio de append. 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 cor-


reto. 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 automa-
ticamente 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 ar-


gumento 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. Programming in Prolog:


using the ISO standard. Springer-Verlag, 5a. edition, 2003. ISBN 3-540-
00678-8.

69

Você também pode gostar