Vous êtes sur la page 1sur 44

Prolog

Introduo
Noes Preliminares
Anterior introduo do Prolog em si, necessrio que tenhamos noes do que h por trs da concepo da linguagem, ou seja, porque e como ela como . Assim, vamos dar uma olhada em duas concepes derivadas da psicologia cognitiva para melhor entendermos para que serviria a linguagem Prolog e como seria sua estruturao. A Relao Define O Mundo Uma primeira concepo pode ser entendida por uma pergunta: o que se relaciona como o qu? Ou: entre que coisas do mundo que conhecemos existe relao? H relao entre este texto e o que estou pensando? H relao entre mim e minha me? H relao entre o motorista do nibus e seus passageiros? H relao entre dois irmos? H relao entre uma caneta que est sobre uma mesa? H uma relao entre uma cala e uma camisa? E assim poderamos continuar interrogando-nos sucessivamente at o infinito... E assim entenderamos que entre todas as coisas que conhecemos existe relao. Obviamente que essa relao pode ser de posio fsica, de posse, de convvio social, de sentimentos, etc. Praticamente no h limites para uma viso de mundo que busca o relacionamento entre os objetos (fsicos ou no) deste mundo. Basicamente, nada existe na mente humana sem relao. No podemos conceber a existncia de um objeto no mundo que no tenha uma relao no tempo e no espao. Tudo relao. A relao entre os objetos que os define no mundo. Como? Qual a definio de rvore para voc? Voc consegue definir um vegetal sem conceb-lo no seu meioambiente? Este o fruto da relao: a rvore (vegetal) relaciona-se com a terra, com o ar e com a luz solar. Sem estas relaes no existe o objeto rvore. Outro exemplo: dois irmos existem por ter pais em comum. Sem a relao de paternidade a definio irmos no existiria. A importncia de considerar-se a relao como definidora dos elementos do mundo o que nos leva a consider-la de extrema utilidade na modelagem de representaes simblicas a nvel computacional. Isto simplifica a modelagem de elementos que so aparentemente complexos por causa de suas relaes, como, por exemplo, a linguagem natural falada pelo homem.

A Classificao e A Seriao Elementos fundamentais para a evoluo cognitiva do homem, a classificao e a seriao permitem o agrupamento para discernimento e a organizao hierrquica dos elementos do mundo. Para entendermos melhor, vamos analisar o comportamento desde o nascimento: h inicialmente nos bebs movimentos de reflexos, que so repetidos durante meses at o momento em que so combinados entre si e outros elementos sensoriais. Isto d incio ao sistema cclico de aprendizado. Uma vez portadora deste sistema, a criana pode distinguir os objetos ao seu redor classificando-os e atribuindo a eles relaes de hierarquia. A classificao e a seriao funcionam paralelamente. O motivo deste funcionamento paralelo foi apresentado no pargrafo anterior: ao distinguir um objeto no mundo, ele definido por sua relao a outros objetos. Inicialmente os bebs no conseguem distinguir entre si mesmos e os objetos do mundo. Eles necessitam da experimentao de suas capacidades sensoriais para, aos poucos, ir formando relaes que permitam a constatao da existncia de objetos isolados e distintos no mundo. Para ns, um bom exemplo o da classificao biolgica dos seres vivos. No caso do homem, sabemos que um mamfero primata humano. Com esta afirmao, indicamos que existem mamferos primatas nohumanos e tambm mamferos no-primatas. Ao realizar a distino entre homens e macacos, faz-se tambm a associao entre suas formas e funes corporais, o que faz presumir que ambos, embora sendo de uma mesma categoria, tm caractersticas distintas. O mesmo ocorre quando comparam-se homens e macacos com outros mamferos noprimatas, e assim sucessivamente. Em decorrncia,temos uma organizao hierrquica onde os humanos esto includos no grupo dos primatas, que, por sua vez est includo no grupo dos mamferos (h p m), estabelecendo, assim,uma seriao. Podemos observar que h relaes entre as diferentes classes, e isso o que permite a definio de cada uma delas. Sem a estrutura de relaes, no existiriam classes e, portanto, no existiria conhecimento. Por qu?A identificao de um objeto no mundo depende de sua diferenciao em relao a outros objetos. Essa diferenciao presume classificao que, por sua vez, presume seriao. O conhecimento depende da distino entre os atributos dos objetos do mundo. Sem a distino, sem o relacionamento, no h conhecimento. Relao define, portanto, conhecimento! Relao no o conhecimento em si, mas um fator fundamental para que o conhecimento exista. necessrio que tenhamos estes conceitos de relaes ao estudarmos Prolog, uma vez que, atravs desta linguagem de programao, iremos representar o mundo atravs de relaes. A programao em Prolog - que significa programao em lgica - no baseada no seqenciamento de procedimentos, mas na definio de relaes, na forma com a qual se representa o mundo que se quer implementar no computador.

Utilizao A linguagem Prolog teve sua concebida por Colmerauer e Roussel em1972, sendo sua primeira verso feita em Fortran por Battani e Meloniem 1973. Desde ento tem sido utilizada para aplicaes de computao simblica, como banco de dados relacionais, compreenso de linguagem natural, automao de projetos, anlise de estruturas bioqumicas e sistemas especialistas. Como podemos perceber, esta linguagem utilizada em tarefas que exijam a representao do conhecimento para execut-las.Aplicaes como os sistemas especialistas e linguagem natural so exemplos claros da utilidade da linguagem Prolog, uma vez que necessitam de regras fornecidas pela experincia humana para que sejam eficientes. Um sistema especialista que necessite realizar um diagnstico precisa que a experincia humana do especialista esteja inserida nas regras de produo para que produza um resultado correto. A lngua natural tambm possui peculiaridades que somente a experincia humana pode traduzir. A estruturao de frases e a semntica inerente a elas fruto do aprendizado, que, at o momento, somente o homem pode reproduzir em regras.

Caractersticas Bsicas
Comandos

Fatos Baseiam-se no seguinte comando: predicado(arg 1[,arg 2,...,arg n]). onde: predicado = relao; arg i = objetos sobre os quais atuam a relao. Um exemplo simples de fato com dois argumentos seria a relao amiga: amiga(joana, maria).

Assim, definimos uma relao (amizade) entre dois argumentos (joana e maria). Obviamente podemos ter um fato com apenas um argumento: homem(carlos). Observe que a relao (homem), quando submetida a apenas um objeto (carlos), torna-se como uma caracterstica daquele objeto. No caso de haver mais argumentos, a ordem de consistncia definida como sendo a atualmente registrada, ou seja, a ltima utilizada. Por exemplo: paga(patrao,salario,empregado). primeira vista parece evidente que a relao(paga) direta entre os dois primeiros objetos (patrao,salario)e indireta ao terceiro (empregado). Esse tipo de interpretao est dependente da ordenao dos objetos declarados nos fatos. Para manter uma coerncia, importante que todos os fatos sigam uma mesma estrutura de interpretao. Assim,no caso da relao amiga talvez fosse mais prudente a declarao bivalente: amiga(joana,maria). amiga(maria,joana). demonstrando a relao amiga tanto no sentido do objeto joana-maria quanto maria-joana. importante salientar que um conjunto de fatos forma um banco de dados. Ou seja, vrias afirmaes compem os dados existentes no sistema. Os fatos so a clula bsica do banco de dados Prolog. Questes A sintaxe de questes varia de acordo com os compiladores existentes, mas basicamente um fato antecedido de um ponto de interrogao ou comando que indique a formulao de uma questo. Por exemplo: ?- amiga(joana, maria). yes A funo da questo basicamente testar a existncia de uma relao sobre os argumentos propostos. No exemplo apresentado, a resposta (yes) foi positiva.

Variveis As variveis so utilizadas de acordo com o comando: pred(arg 1,Var 1[,arg/Var 2,...,arg/Var n]). ou pred(Var 1,arg 1[,arg/Var 2,...,arg/Var n]). onde Var = varivel (deve comear com letra maiscula). A varivel o elemento mais til para a formulao de questes. Por exemplo: ?- amiga(joana,Quem). Quem = maria Em cima das questes com variveis que sero construdos os sistemas mais complexos de estruturao da representao de conhecimentos. Conjuno A conjuno permite a composio de fatos, formando o chamado e lgico: pred(arg/Var,arg/Var),pred(arg/Var,arg/Var). A vrgula ( , ) entre as questes determinam a validade mtua de ambas (ou do conjunto envolvido). O objetivo da conjuno a realizao de uma busca no banco de dados para a verificao da validade da questo ou busca dos objetos relacionados com os argumentos propostos. O mecanismo de busca uma estratgia de controle do tipo busca em profundidade com retrocesso . Assim, dados os seguintes fatos: amiga(joana,maria). amiga(clara,maria). E a questo: ?- amiga(joana,Quem),amiga(clara,Quem). Quem = maria

Como podemos perceber, a consulta teve como objetivo obter o objeto (maria) que faltava para validar a conjuno entre os dois objetivos. Objetivo, neste contexto, cada um dos componentes da conjuno. H duas formas de validao de conjunes. A primeira ocorre caso todos os objetivos sejam fatos como, por exemplo: ?- amiga(joana,antonia),amiga(maria,clara). no todos os objetivos devem ser validados. A segunda forma ocorre, como j foi visto, caso hajam variveis e existam correspondentes entre as variveis dos objetivos. Para facilitar a compreenso da construo da conjuno, ela pode ser vista como uma estrutura em rvore,onde os objetos so folhas das relaes, as quais esto ligadas questo, que torna-se a raiz da rvore.No caso da questo cujo objeto maria era a incgnita, temos como nodos filhos da raiz os predicados da relao amiga,e de cada relao partem duas folhas com os objetos. Atravs da varredura desta rvore podemos deduzir que a varivel Quem referia-se ao objeto maria , comum em ambos objetivos,tornando, deste modo, a questo vlida. Regras o comando na forma: pred(arg/Var,arg/Var) :- pred(arg/Var,arg/Var). onde o smbolo :- indica a uma condio (se) ou, no caso de compararmos com lgica de predicados, a uma implicao material. A regra o instrumento bsico de organizao do banco de conhecimentos e permite a construo de questes complexas (formas mais sofisticadas de consulta ao banco de dados). ela que indica a validade de um conjunto de fatos, questes ou conjunes. Para exemplificar o uso da regra, vamos inicialmente declarar alguns fatos: amiga(joana,maria). amiga(maria,joana). amiga(maria,clara). amiga(clara,maria). ama(joana,maria). ama(maria,joana). E a regra amiga_intima:

amiga_intima(Ela1,Ela2) :amiga(Ela1,Ela2), amiga(Ela2,Ela1), ama(Ela1,Ela2), ama(Ela2,Ela1). Desta forma, seria verdadeira a questo: ?- amiga_intima(maria,joana). yes E falsa a questo: ?- amiga_intima(maria,clara). no Percebemos, ento, que h a possibilidade de construo de produes complexas em cada regra, permitindo conceitos cada vez maiores e consultas com um maior nvel de definio e de variveis. Disjuno A disjuno o oposto da conjuno,equivale ao ou lgico: pred(arg/Var,arg/Var) :- (pred(); atrib;...). No exemplo: amiga(X) :- (X=maria; X=joana). Uma consulta seria: ?- amiga(celia). no Ou: ?- amiga(Quem). Quem = maria Quem = joana Como podemos observar, o ponto-e-vrgula ( ; ) permitea aceitao de uma ou outra

condio para avalidao da clusula, enquanto o operador de conjuno( , ) implica na necessidade de aceitao de todasas condies.

Operadores Numricos

Relacionais Operadores numricos relacionais so aqueles usados para realizar testes quantitativos entre dois nmeros. So eles:

= < =<

\= > >=

Ou seja, os smbolos so: igual (X = Y), diferente (X \= Y), menor (X < Y), maior (X > Y), menor ou igual (X =< Y) e maior ou igual (X >= Y). Observe que o smbolo menor ou igual segue a ordem inversa de seu nome. Apesar dessas afirmaes, nem todos os compiladores Prolog seguem esta verso. sempre prudente observar o manual do compilador para ver se ele segue este padro. H verses em que,por exemplo, a diferena dada pelo sinal <>. Um exemplo da utilidade dos operadores relacionais: dentro_interv_aberto(K,X1,X2) :K > X1, K < X2. E a questo: ?- dentro_interv_aberto(5,0,5). no Como se v, h diversas possibilidades de criaode regras matemticas utilizando os operadores relacionais.

Aritmticos Operadores aritmticos so os utilizados na aritmticabsica:

+ * mod

/ is

Ou seja: soma (X + Y), subtrao (X - Y), multiplicao(X * Y), diviso (X / Y), mdulo (X modY) e resultado (X is equao ). Por exemplo: ao_quadrado(X,Y) :Y is X*X. E a questo: ?- ao_quadrado(6,X). X = 36 Deste modo, percebemos que h a possibilidade de construode diversas funes matemticas mais complexas a partirde regras e operadores aritmticos. H funesmatemticas mais complexas j implementadas em Prolog quesero analisadas posteriormente.

Estruturas de Dados

As estruturas de dados ocorrem na forma: pred(arg, estrut(atrib1,...,atrib n)). ou pred(estrut(atrib1,...,atrib n), arg). As estruturas servem para aninhar dados de forma organizada, estruturada.Elas permitem a distino de atributos para um argumento.Um exemplo de uma estrutura simples seria: ficha(num,func(nome,end,cargo)).

Os tomos nome , end , cargo soos componentes da estrutura func , o que permite o armazenamentode atributos do funcionrio de uma empresa, por exemplo. Mas podemosfazer mais nveis de aninhamento: ficha(num,func(dados_pes(nome,end),cargo(funcao,salario(basico,descontos,vantagens)))). Nesta linha de cdigo temos a definiode uma ficha cadastral, cuja chave um nmero que permiteo acesso aos dados de um funcionrio: seus dados pessoais e seucargo na empresa. Os dados pessoais resumem-se ao nome e endereodo funcionrio. O cargo compe-se da funoexercida e do salrio ganho. O salrio calculadoem termos do vencimento bsico, descontos e vantagens acumuladas. Obviamente, este fato deve estar com os dados j preenchidos: ficha(001,func(dados_pes('Fulano de Tal','Rua Epa'),cargo('continuo',salario(100,30,10)))). Assim, temos um exemplo exagerado de aplicaode estruturas Prolog. Obviamente que uma aplicao real paraa produo de um sistema de gerenciamento de banco de dadosteria uma maior preocupao com a clareza de distribuiodos dados, evitando o aninhamento excessivo. Podemos ainda construir expresses com variveis dotipo: pred(estrut(atrib,Var),Var). que podem ser representadas na forma:

Como podemos ver, a estrutura de dados j criadaem qualquer tipo de comando Prolog, de forma que devemos ter em mente sempreesta estruturao para mais facilmente compreendermos a funodo comando que estamos analisando ou trabalhando. Obviamente as estruturas em Prolog no resumem-se forma de seus comandos. Podemos construir estruturas de dados mais complexaspara auxiliar na implementao de aplicaes.

Listas A forma mais adequada para estruturao de dados emProlog so as listas. Como o nome diz, so estruturas dinmicasde armazenamento de dados. Elas so utilizadas na

construode vetores e matrizes dinmicos de caracteres, nmeros, equaisquer outros dados utilizados. Apresentam-se na forma: pred([elem,...],[],[elem[elem,..],...],arg,...). onde elem pode ser qualquer tipo sinttico. Um conceito importante para a utilizao das listas o cabea-corpo ( | ). Ele usado para isolarmembros de uma lista. Por exemplo, dada uma lista na forma: lista([a,b,c,d,e]). Aplicando-se a questo: ?- lista([X | Y]). X=a Y=[b,c,d,e] Como podemos observar, o operador | permite a separaoda cabea da lista de seu corpo. Isso permite o isolamento dos membrosda lista, facilitando sua anlise. As listas so tipos peculiares de estruturas de dados quetambm podem ser representadas atravs de rvores.Esse tipo de representao muito til quandotrabalhamos com altos nveis de aninhamento. Como, por exemplo: ficha(123,func(dados_pes([["Silva","Fulano da"],["solteiro",0]], ["ruaTal",99,301]),cargo( ["continuo"],[minimo,1]))). A rvore para representar esta linha de cdigo seria:

Podemos observar, neste exemplo extremado, a aparente complexidadeprovocada pela leitura da linha de cdigo que desfeitaquando representada em rvore. Nesta representaovemos uma nova simbologia com a visualizao do ponto ( .), que faz a indicao dos nodos da lista; e da lista vazia( [] ), que indica o final da lista (NULL). Como dito anteriormente,este um bom recurso para a visualizao de expressescom um maior

nvel de complexidade, facilitando sua anlisee compreenso. As listas so o principal tipo de estrutura de dados em Prolog,com as quais possvel a construo de vetorese matrizes, com a vantagem de ser uma estrutura de memria dinmica. Programa-exemplo 1: Verifica se uma palavra palndroma. Exemplo de utilizao: inicio. <enter> madam.<enter> % entrada e saida de dados inicio :- read(X), (X = para; teste(X), inicio). teste(X) :- nome(X,N), palindromo(N), write(X), write(` eh palindroma'),nl, !. teste(X) :- write(X), write(` nao eh palindroma'), nl. % inversao e teste palindromo(X) :- inverte(X,X). inverte(L1,L) :- invconc(L1,[ ],L). invconc([H|T],L,M) :- invconc(T,[H|L],M). invconc([ ], L, L). Programa exemplo 2: Implementa o mtodo de ordenao da bolha.Uso: bolha([4,56,8,10],X). bolha(L, S) :concatena(U, [A, B|V], L), B > A, !, concatena(U, [B, A|V], M), bolha(M, S). bolha(L,L).

concatena([],X,X). concatena([X|Y],Z,[X|W]) :- concatena(Y,Z,W). Pilhas Em Prolog h mais de uma forma de se implementar uma estrutura para funcionamento no mtodo LIFO. O que apresentado a seguir apenas uma das formas, a de mais fcil manipulao.Ela tem a forma: ...s(elem1,elem2)... Onde s indica uma pilha (stack) e elem pode ser qualquer tipo sinttico.Observe que h dois componentes, sendo que o primeiro indica a posiono topo da pilha e o segundo o restante (se houver) da estrutura. Os pontosantes e depois indicam que este um trecho de predicado, ou seja,seu uso no isolado, como demonstram os exemplos de manipulaoa seguir. Antes de utilizarmos uma pilha, temos que defini-la: pilha(s(X,Y),X,Y). Para manipularmos, podemos realizar operaes de retirada e insero de pilha. Um exemplo de retirada o seguinte: ?- pilha(s(a,s(b,s(c,0))),X,Y). X=a Y = s(b,s(c,0)) Este predicado est retirando o topo, que o elemento a. Para insero de um elemento i no topo da pilha: pilha(E,i,s(a,s(b,s(c,0)))). E = s(i,s(a,s(b,s(c,0)))) Como vimos, nos dois exemplos h as variveis para retorno das estruturas transformadas. Observe tambm que so trabalhados 3 elementos no predicado: quando queremos retirar, o primeiro elemento a pilha original, quando queremos inserir, o primeiro elemento a pilha final. Filas

A representao da fila semelhante da pilha. Ela tem a forma: ...q(elem1,elem2)... Onde q indica uma fila (queue) e elem qualquer tipo sinttico.Como na pilha, h dois componentes, sendo que o primeiro indicao primeiro da fila e o segundo representa o restante (se houver) da estrutura.Os pontos antes e depois indicam que este um trecho de predicado,como veremos nos exemplos a seguir. Podemos manipular a fila atravs da inseroou retirada. A retirada se d no incio da fila, e a inserono fim. Para definir a retirada, devemos estabelecer o seguinte predicado: retira_fila(q(E,Re),E,Re). Um exemplo de utilizao desta definio o seguinte: ?- retira_fila(q(a,q(b,q(c,0))),a,F). F = q(b,q(c,0)) Neste exemplo, desejou-se retirar o elemento a da estrutura, queera o primeiro da fila. A fila alterada retornada em F. A definio de insero aseguinte: insere_fila(F,q(R,E),R,F). Na fila a seguir, ir ser inserido um novo elemento, d,que ir para o final da fila: ?- insere_fila(q(a,q(b,q(c,X))),X,d,F). F = q(a,q(b,q(c,q(d,X)))) Correntes Nesta seo, entende-se correntes por listas ligadas.O nome foi alterado por no serem listas ligadas, mas sim um recursopara representar uma estrutura com o mesmo princpio. As correntes tem uma forma semelhante pilha e fila: ...c(elem1,elem2)... Onde c indica uma corrente (chain) e elem qualquer tipo sinttico.Como na pilha e na fila, h dois componentes, sendo que o primeiroindica o primeiro elemento da corrente e o segundo representa o restante(se houver) da estrutura.

A seguir, veremos exemplos de retirada, inseroe inverso de lista. Para retirada, temos a seguinte definio: retira_lista(A,c(A,X),X) :-!. retira_lista(A,c(X,Y1),c(X,Y2)) :- retira_lista(A,Y1,Y2). Um exemplo de retirada de um elemento do meio da corrente: ? - retira_lista(b,c(a,c(b,c(c,nil))),L). L = c(a,c(c,nil)) Para insero, temos a definio: insere_lista(A,B,c(B,X1),c(A,c(B,X1))). insere_lista(A,B,c(C,X),c(C,X1)) :- insere_lista(A,B,X,X1). Exemplificando, para inserir um elemento entre outros dois: ? - insere_lista(b,c,c(a,c(c,nil)),L). L = c(a,c(b,c(c,nil))) Uma outra definio auxiliar a de inversode corrente: inverte_lista(X,X,Z,Z). inverte_lista(c(U,V),X,Y,Z) :- inverte_lista(V,X,c(U,Y),Z). A utilizao da definio de inverso como mostrado a seguir: ? - inverte_lista(c(a,c(b,c(c,x))),x,x,Z). Z = c(c,c(b,c(a,x))) rvores Como nas estruturas analisadas anteriormente, possveluma representao de rvore em Prolog que no semelhante s linguagens procedurais, que utilizam procedimentos.Uma forma de representao de rvore binria a seguinte: ...t(ramo1,raiz,ramo2)...

Onde t indica uma estrutura em rvore (tree), ramo1 representaa derivao esquerda da rvore e ramo2 a derivao direita. Uma operao possvel em rvore a troca de uma subrvore por outra. A definio detroca de subrvore : troca_sub(A,S,S,A). troca_sub(A,S,t(T1,X,R2),t(T1,X,R1)):- troca_sub(A,S,T1,T2). troca_sub(A,S,t(T1,X,R1),t(T1,X,R2)):- troca_sub(A,S,R1,R2). A execuo desta definio pode serdemostrada atravs da questo: ? - troca_sub(t(o,k,p),t(h,d,i),t(t(t(h,d,i),b,e),a,t(f,c,g)),A). A = t(t(t(o,k,p),b,e),a,t(f,c,g)) Neste exemplo, a subrvore com raiz no elemento d foi substitudapor outra, com raiz k. A varivel A apresenta a nova rvore. Estas foram as estruturas bsicas de dados que somanipulados em Prolog. Para as formas apresentadas de pilha, fila, correntee rvore possuem determinadas letras definindo as estruturas. Estasletras so apenas indicadores, podendo ser trocadas por outras letras.Por outro lado, as letras apresentadas (s, q, c, t) so convenespara melhor situar o programador em que tipo de estrutura est sendomanipulada. Outra observao pertinente lembrar queestas ltimas estruturas so variaes de utilizaoda estrutura elementar, apresentada no incio desta seode estruturas de dados. Vale revisar as estruturas variantes para melhorcompreender seu funcionamento.

Corte de Fluxo
H ocasies em que, por um ou outro motivo, nodesejamos a continuidade da verificao das regras. Paraestes casos usamos um mecanismo para corte do fluxo, simbolizado por umponto de exclamao ( ! ). A seguir veremos trscasos em que o corte utilizado. Escolha de uma regra O corte til quando sabemos que uma determinadaregra a ltima a ser analisada e haveria problemas na continuidadede verificao das demais regras. Por exemplo, uma implementaode funo fatorial:

fat(0,1) :- !. fat(N,R) :- Ni is N-1, fat(Ni,Ri), R is Ri*N. Observe que a ltima clusula vlida narecurso a do fatorial de zero. Esta ltima clusula marcada pelo corte, informando que no necessriaa continuidade do clculo. Programa-exemplo 3: Verifica igualdade entre duas listas. Exemplo: verifica_igual([a,3,1,d,v],[a,d,v,1,3]). verifica_igual(X, X) :- !. verifica_igual(X, Y) :- igual(X, Y). % faz a troca igual([X|L1],[Y|L2]) :- retira(X, L2, L3), igual(L1, L3). igual([],[]). % compara por eliminacao retira(X,[Y|L1],[Y|L2]) :- retira(X,L1,L2). retira(X,[X|Y],Y). Programa-exemplo 4: Subtrao de duas listas. Exemplo de uso: subtract([a,c,b],[a,b],X). subtrai(L,[],L) :- !. subtrai([H|T]) :- membro(H,L), !, subtrai(T,L,U). subtrai([H|T],L,[H|U]) :- !, subtrai(T,L,U). subtrai(_,_,[]). membro(Cab,[Cab|_]). membro(Elem,[_|Corpo]) :- membro(Elem,Corpo).

Combinao corte-falha Para acelerar a avaliao de regras (e desta forma tambm economizar memria), podemos combinar o corte como predicado fail . Este um predicado interno ao Prolog que fora um retrocesso na avaliao das regras,como se indicasse uma falha. O predicado em si no tem muito sentido ,mas quando utilizado com o corte, mostra-se muito til. Por exemplo: calculo_medias(X,Y,Z,R):- R = X*0.5+Y*0.3+Z*0.2, R < 1000, !, fail. calculo_medias(X,Y,Z,R):- R = X*0.3+Y*0.5+Z*0.2, R < 5000, !, fail. calculo_medias(X,Y,Z,R):- R = X*0.2+Y*0.3+Z*0.5. Aqui temos trs formas de realizar um determinado clculo,com fatores aplicados dependendo da faixa do resultado. Poderia ser, por exemplo, uma espcie de clculo salarial. Caso o valor da primeira regra fosse menor que 1000, ento no seria necessria a investigao das demais regras, uma vez que este o clculo correto. O mesmo vale para a segunda regra, restando apenas a opo da terceira.

Gerao e Teste Mais uma utilidade do corte possibilitar o encerramento de implementaes com infinitas avaliaes de regras. Em programao convencional isto seria chamado de lao infinito, e em Prolog a recurso tambm faz parte da avaliao das regras. H programas que correm o risco de executarem indefinidamente se no houver um teste deparada. Isso ocorre na seguinte implementao: inteiro(0). inteiro(N) :- inteiro(K),N is K+1. diviso (N1,N2,R):- inteiro(R), P1 is R*N2, P2 is (R+1)*N2, P1 =< N1, P2> N1, !. A funo deste cdigo realizara diviso inteira de dois nmeros, embora seja uma implementao no-eficiente. Esta implementao usa um gerador de nmeros inteiros (predicado inteiro) e testes de compatibilidade.Quando os testes so concordantes, o resultado devolvido.A lgica simples: vo sendo gerados todos os nmeros inteiros at que se encontre um que, multiplicado pelo divisor,seja igual ou maior que o dividendo.

Predicados Incorporados
Prolog est provido de predicados bsicos que possibilitamuma estrutura mnima de funcionamento, como os de entrada e sada, consulta e insero . Aqui importanteobservar que estes predicados podem variar de uma verso para outrade compiladores/interpretadores Prolog. Os predicados aqui apresentadosso de uma verso standard, o que implica que poderono existir ou estarem implementados sob diferentes formas em outrasverses mais sofisticadas de Prolog.

Entrada e Sada

get0(X) / get(X) So os predicados utilizados para leitura de caracteres escritosno teclado e comparao com a varivel X. A diferenaentre ambos que get0 pega todos os caracteres digitadose get salta os caracteres no-imprimveis. Sua utilizao,no entanto, restrita leitura de um caracter por vez. read(X) Este predicado destina-se leitura de termos do teclado.Todo o termo escrito deve terminar com um ponto ( . ). Este termo podeser uma palavra isolada, uma lista de letras ou ainda um string de caracteres.Por exemplo, dada a regra: oi :- read(X), write('Resposta: '), write(X). E a questo: ?- oi. ola. Resposta: ola O termo ola encarado aqui como um argumento que ser associado varivel X. Por outro lado: ?- oi. Ola. Resposta: _00A0 Isso demonstra que Ola, neste contexto, foi considerado uma varivel que est sendo associada X. J no caso de lista de caracteres, temos:

?- oi. "Ola, como vai?". Resposta: [79,108,97,44,32,99,111,109,111,32,118,97,105,63] Neste caso, o termo uma lista com os caracteres que esto entre aspas. Se ao invs de aspas colocarmos apstrofos,teremos outro tipo de termo: ?- oi. 'Ola, como vai?'. Resposta: Ola, como vai? Vemos, assim, que h diversas variantes para a utilizaodo read, dependendo da aplicao que temos em vista. put(X) Imprime apenas um caracter por vez. A varivel X deve conter um inteiro correspondente ao caracter que se quer imprimir. write(X) Imprime termos associados a X. So vlidas as mesmas observaes feitas para read. Por exemplo, seja a regra: esc(X) :- write(ola), nl, write(X), nl, write("Ola"),nl, write('Ola'). E a questo: ?- esc(ola). ola ola [79,108,97] Ola display(X) Tem funes idnticas a write, porm distingue os temos sintticos. Por exemplo, dada a regra: esc2 :- write(a+b*c), tab(5), display(a+b*c), nl, write([oi,oi]),tab(5), display([oi,oi]).

E a questo: ?-esc2. a + b *c '+'(a,'*'(b,c)) [oi,oi]'.'(oi,'.'(oi,[])) Vemos, pois, que o predicado display apresenta os termos na ordem de tratamento que Prolog d a eles. nl Provoca a quebra da linha, sendo que o prximo comando de impresso iniciar numa nova linha. tab(X) Coloca uma quantidade de espaos em branco determinada pelo valor de X. skip(X) Processa at que o caracter igual a X seja encontrado.

Manipulao de Arquivos

tell(X) Cria um arquivo de sada X. telling(X) Verifica se X o atual arquivo de sada . told Fecha o arquivo de sada aberto. see(X)

Abre um arquivo de entrada existente. seeing(X) Verifica se X o atual arquivo de entrada . seen Fecha o arquivo de entrada aberto.

Consulta e Insero
consult(X) Realiza uma consulta a um determinado banco de dados X. Esta consultaconsiste em carregar o contedo de X para a memria. Umavez consultado o banco de dados, os fatos e regras nele contidos poderoser mencionados. O banco de dados X geralmente um arquivo texto: ?-avo(Avo,gabriel). no ?-consult('familia.ari'). yes ?-avo(Avo,gabriel). Avo= fulgencio Nesse exemplo, a primeira questo no foi possvelser respondida pela falta do banco de dados 'familia.ari'. Uma vez consultado,ele fica residente na memria e a questo pode ser respondida. reconsult(X) um predicado complementar a consult . Ele tem afuno de trocar fatos e regras que tenham sido modificadosde um banco de dados X residente na memria (j consultado).O predicado consult pode ser usado para a releitura do banco dedados, mas ele ser replicado na memria, o que promoverum erro de avaliao das regras. O predicado reconsulttem a vantagem de alterar apenas o que foi modificado no arquivo do bancode dados.

listing(A) Permite a listagem de uma determinado predicado que estsendo utilizado. Por exemplo: ?- listing(avo). avo(Avo,Neto):macho(Avo), casal(Avo,_), filho(Filho,Avo), pai(Filho,Neto). asserta(X) / assertz(X) Estes predicados servem para inserir um novo fato X no banco dedados residente na memria. (Observe que a alterao somente a nvel de memria). A diferenaentre ambos que asserta insere o fato no incio do bancode dados e assertz faz a insero ao final do banco. Porexemplo: ?- consult('familia.ari'). yes ?- listing(filha). filha(juliana,marcos). filha(juliana,mariana). ?- asserta(filha(marcia,marcos)). yes ?- assertz(filha(marcia,mariana)). yes ?- listing(filha). filha(marcia,marcos). filha(juliana,marcos). filha(juliana,mariana). filha(marcia,mariana). Nesse exemplo, foi inserido um fato no incio do banco dedados e outro no final. Na ltima listagem podemos observar os fatosj existentes junto aos novos. retract(X) Realiza a retirada de um fato X do banco de dados existente na memria. o oposto a asserta / assertz .

Negao
not(X) o predicado em que tem sucesso quando X falha. Por exemplo: ?- not(macho(mariana)). yes

Repetio
repeat Realiza a repetio da regra at que a prximaclusula seja vlida. Por exemplo, dada a regra: pega2(X) :- repeat, get0(X). pega(X) :- pega2(X), X > 32, !. A regra pega ser repetida at que a entrada seja um caracterimprimvel.

Regras Gramaticais

Prolog prov recursos especiais para facilitar a implementaode regras gramaticais de gramticas livres de contexto. Para exemplificar, podemos estruturar as regras de frases simplesem portugus: esta frase divide-se em sintagma nominal e sintagmaverbal; o sintagma nominal pode ser formado por um artigo e por um substantivo;o sintagma verbal pode ser formado por apenas um verbo ou por um verboe outro sintagma nominal. Na forma Prolog que vimos at agora, issopoderia ser descrito assim: frase(S0,S) :- sn(S0,S1), sv(S1,S). sn(S0,S) :- art(S0,S1), subs(S1,S). sv(S0,S) :- verbo(S0,S). sv(S0,S) :- verbo(S0,S1), sn(S1,S). art([o|S],S).

art([a|S],S). subs([homem|S],S). subs([flor|S],S). verbo([colhe|S],S). verbo([canta|S],S). Ou, na forma facilitada: frase --> sn, sv. sn --> art, subs. sv --> verbo. sv --> verbo, sn. art --> [o]. art --> [a]. subs --> [homem]. subs --> [mulher]. subs --> [flor]. verbo --> [colhe]. verbo --> [canta]. Uma questo poderia ser: ?- frase([a,mulher,colhe,a,flor],[]). yes Como vemos, a construo de gramticas torna-sesimplificada e clara, conforme a notao usual. Prolog ,portanto, uma ferramenta por excelncia para a estruturaode gramticas, possibilitando a implementao de linguagenspara diversas aplicaes.

Apndice A - Mais Exemplos de Programas


Problema da Torre de Hani %:- module towers. %:- public towers/0. towers :-

repeat, write('Number of rings (or ctl-c to end): '), read(X), hanoi(X), fail. hanoi(N) :- move(N,left,center,right), !. move(0,_,_,_) :- !. move(N,A,B,C) :M is N-1, move(M,A,C,B), inform(A,B), move(M,C,B,A). inform(A,B) :- write([move,disk,from,A,to,B]), nl. Problema das 9 rainhas /* This program places n queens on a chess board by exhaustive search. For this reason it takes awhile, taking slightly over three minutes to place 8 queens using a 6 Mhz AT type machine. */ /* write("Enter the number of queens.\nMore than 3 and less than 9."),nl, readint(Num),

clearwindow, writef("solving the % queens problem.",Num),nl, write("[ctrl][break] to stop"),nl, time(_,M1,S1,H1), writef("start time: %:%.%\n",M1,S1,H1), nqueens(Num), time(_,M2,S2,H2),nl, writef("end time: %:%.%\n",M2,S2,H2). */ nqueens(N):makelist(N,L),Diagonal=N*2-1,makelist(Diagonal,LL), placeN(N,board([],L,L,LL,LL),board(Final,_,_,_,_)),write(Final). placeN(_,board(D,[],[],D1,D2),board(D,[],[],D1,D2)):-!. placeN(N,Board1,Result):place_a_queen(N,Board1,Board2), placeN(N,Board2,Result). place_a_queen(N,board(Queens,Rows,Columns,Diag1,Diag2), board([q(R,C)|Queens],NewR,NewC,NewD1,NewD2)):findandremove(R,Rows,NewR), findandremove(C,Columns,NewC), D1=N+C-R,findandremove(D1,Diag1,NewD1), D2=R+C-1,findandremove(D2,Diag2,NewD2). findandremove(X,[X|Rest],Rest).

findandremove(X,[Y|Rest],[Y|Tail]):findandremove(X,Rest,Tail). makelist(1,[1]). makelist(N,[N|Rest]):N1=N-1,makelist(N1,Rest). Busca de Caractersticas Comuns /* This program will find pairs. Enter the goal: findpairs. */ findpairs if person(Man, m, ILIST1 ) , person( Woman, f, ILIST2 ) , common_interest( ILIST1, ILIST2, _ ) , write( Man, " might like ",Woman ) , nl , fail. findpairs:- write ("---end of the list---\n"). common_interest( IL1, IL2, X ) if member(X, IL1 ) , member(X, IL2) , !. person(tom,m,[travel,books,baseball]). person(mary,f,[wine,books,swimming,travel]). member( X, [X|_] ). member( X, [_|L] ) if member( X, L ). Programas com listas

%%% %%% LISTS %%% %%% DECLARATIONS /*:- public member/2, member_check/2, append/3, intersection/3, subset/2, prefix/3, suffix/3, insert_sort/2, bubble/2, mergesort/2, quicksort/2, sublist/4, merge/3, sorted/2, flatten/2, last/2, list_search/3, nrev/2, reverse/2, delete/3, list_insert/3, writel/1, number_occurrences/3, remove_duplicates/2, divide/3. :- visible member/2, member_check/2, append/3, intersection/3, subset/2, prefix/3, suffix/3, insert_sort/2, bubble/2, mergesort/2, quicksort/2, sublist/4, merge/3, sorted/2, flatten/2, last/2, list_search/3, nrev/2, reverse/2, delete/3, list_insert/3, writel/1, number_occurrences/3, remove_duplicates/2,

divide/3. */ %%% member(?Element,+List) %%% The member predicate checks whether Element is a member of List. %%% If you supply an uninstantited variable for Element, then each of %%% the members of the list is returned through backtracking. %:- mode member(?,+). member(H, [H|_]). member(H, [_|T]) :member(H, T). %%% member_check(+Element,+List) %%% The member_check predicate checks whether Element is a member ofList. %%% However, the member_check predicate does not backtrack and thusonly %%% returns a single answer. % :- mode member_check(+,+). member_check( H, [H|_]) :- !. member_check(H, [_|T]) :member_check(H, T). %%% append(?List1,?List2,?List3) % :- mode append(?,?,?). append([],L,L). append([H|T], L, [H|R]) :append(T, L, R).

%%% intersection(+List1,+List2,-/+Intersect) %%% The intersection predicate lists the intersection (common elements) %%% of two lists. % :- mode intersection(+,+,-/+). intersection([], _, []) :!. intersection([H|L1], L2, [H|L3]) :member(H, L2), intersection(L1,L2,L3), !. intersection([_|L1],L2,L3) :intersection(L1,L2,L3). %%% subset(+Subset,+List) %%% The subset predicate succeeds if the list provided as Subset isa %%% subset of the list provided as List. % :- mode subset(+,+). subset( [], _ ). subset( [A|X], Y ) :member( A, Y ), subset( X, Y ). %%% prefix(+List1,+List2,-/+Prefix) %%% The prefix predicate compares two lists from the beginning of %%% each list and returns a list containing the elements that are

%%% prefixes for both lists. %%% % :- mode prefix(+,+,-/+). prefix([],_,[]) :!. prefix(_,[],[]) :!. prefix([H|T1], [H|T2], [H|T3]) :!, prefix(T1, T2, T3). prefix(_, _, []). %%% suffix(+List1,+List2,-/+Suffix) %%% The suffix predicate compares two lists from the end of each list %%% and returns a list containing the elements that are suffixes for %%% both lists. % :- mode suffix(+,+,-/+). suffix(L, L, L ) :- !. suffix( [H|T1], [H|T2], [H|T3] ) :!, suffix( T1, T2, T3 ). suffix( _, _, [] ). %%% insert_sort(+List,-/+Sorted) %%% Converts a list into a sorted list using an insertion sort. In an

%%% insertion sort, an individual element is taken from List and %%% compared with successive elements in the sorted list to determine %%% where it should be placed in the sorted list. %%% % :- mode insert_sort(+,-/+). insert_sort([], []). insert_sort([H|T], L2) :insert_sort(T, L1), insert(H, L1, L2). insert(X, [H|T], [H|L]) :X @>= H, !, insert(X, T, L). insert(X,L,[X|L]). %%% bubble(+List,-/+Sorted) %%% Converts a list into a sorted list using a bubble sort. In a %%% bubble sort, two adjacent elements are compared to see if they %%% are out of order. If so, their order is changed and the pair %%% comparison continues. In this way, elements that are out of order %%% "bubble" up to their place in the list. % :- mode bubble(+,-/+). bubble(L1,L2) :append(U, [A,B|V], L1),

B @< A, !, append(U, [B,A|V], M), bubble(M, L2). bubble(L1,L1). %%% mergesort(+List,-/+Sorted) %%% Converts a list into a sorted list using a merge sort. In a merge %%% sort a list is first divided into two lists whereby the first %%% element of List becomes part of list1, the second element of List %%% becomes part of list2, the third element of List becomes part of %%% list1, and so on. The new lists are further divided until single %%% element lists are created. The single element lists are compared %%% and merged according to which element should come first. Merging %%% continues until the whole list is recreated as a sorted list. % :- mode mergesort(+,-/+). mergesort([], []) :- !. mergesort([A], [A]) :- !. mergesort(List, SortList) :divide(List, L1, L2), mergesort(L1, S1), mergesort(L2, S2), merge(S1, S2, SortList). %%% quicksort(+List,-/+Sorted)

%%% Converts a list into a sorted list using a quick sort. In a quick %%% sort, the list is split at an arbitrary point. All the elements %%% greater than the element at the split point are placed in one %%% list, and all the elements less than the element at the split %%% point are placed in another list. Then each of the resultent %%% lists are themselves quick sorted. The sorted lists are appended %%% to create the full sorted list. % :- mode quicksort(+,-/+). quicksort([],[]) :- !. quicksort([H|T], Sort) :split(H, T, Less, Greater), quicksort(Less, LSort), quicksort(Greater, GSort), append(LSort, [H|GSort], Sort). %%% split( +Divisor, +List, -/+Less, -/+Greater %%% split a List into those elements which are Less than a Greater than %%% some divisor. % :- mode split( +, +, -/+, -/+ ). split(_, [], [], []) :- !. split(Test, [H|Tail], [H|Less], Greater) :H @< Test, !, split(Test, Tail, Less, Greater).

split(Test, [H|Tail], Less, [H|Greater]) :split(Test, Tail, Less, Greater). %%% sublist(+Offset,+Length,+List,-/+Sublist) %%% The sublist predicate returns a sublist of the length you %%% specify. The Offset argument indicates where the sublist should %%% start. Elements in a list are numbered from 0, so an offset of 4 %%% will return a sublist beginning at the fifth element in the list. % :- mode sublist(+,+,+,-/+). sublist(0, 1, [H|_], [H]) :- % [] is not a sublist !. sublist(0, Len, [H|L1], [H|L2]) :!, dec(Len, Len1), sublist(0, Len1, L1, L2). sublist(Off, Len, [H|L1], L2) :dec(Off, Off1), sublist(Off1, Len, L1, L2). %%% merge(+List1,+List2,-/+Merged) %%% The merge predicate merges two lists together. To merge the %%% lists, the first element in List1 is compared to the first %%% element in List2. The element that ranks higher in the standard %%% order is added to the Merged list. Then, the first elements of %%% each list are compared again. Comparison of the first elements in

%%% the list continues until all elements have been compared and %%% merged or until one list is empty, in which case the elements of %%% the remaining list are appended to the Merged list. % :- mode merge(+,+,-/+). merge([],L,L) :- !. merge(L,[],L) :- !. merge([H1|L1], [H2|L2], [H1|L3]) :H1 @=< H2, !, merge(L1, [H2|L2], L3). merge(L1, [H2|L2], [H2|L3]) :merge(L1, L2, L3). %%% sorted(+List) %%% The sorted predicate succeeds if List is a sorted list. % :- mode sorted(+). sorted([]) :- !. sorted([_]) :- !. sorted([A,B|_]) :B @< A, !, fail. sorted([_|T]) :sorted(T).

%%% flatten(+List,-/+Flattened) %%% The flatten predicate eliminates all sublists by making the elements %%% of each sublist individual elements of the overall list. % :- mode flatten(+,-/+). flatten([],[]) :!. flatten([H|T], List) :!, flatten(H, H1), flatten(T, T1), append(H1, T1, List). flatten(X, [X]). %%% last(+List,-/+Last) %%% The last predicate returns the last element in a list. % :- mode last(+,-/+). last(List, Last) :append(_, [Last], List). %%% list_search(+SubList,+List,-/+Offset) %%% The list_search predicate indicates where in a list that a %%% sublist begins. The starting position of the sublist is returned %%% as an integer to the Offset argument. Note that the elements ofa %%% list are numbered from 0, so, for example, the fifth element ofa %%% list is at offset 4.

% :- mode list_search(+,+,-/+). list_search(L1, L2, Off) :list_search(L1, L2, 0, Off). list_search(_, [], _, _) :- % end - no more sublists found !, fail. list_search(L, L2, Off, Off) :- % sublist found append(L, _, L2). list_search(L1, [H|L2], N, Off) :inc(N, N1), list_search(L1, L2, N1, Off). %%% nrev(+List,-/+Reverse) %%% The nrev predicate reverses the elements in a list by recursively %%% appending the head of the list to its tail. This type of list %%% reverasal is commonly known as naive reverse. % :- mode nrev(+,-/+). nrev([],[]). nrev([H|T], Reverse) :nrev(T, L1), append(L1, [H], Reverse). %%% reverse(+List,-/+Reverse) %%% Like the nrev predicate, the reverse predicate reverses a list. %%% However, the reverse predicate uses an "accumulator" tostore

%%% intermediate results. The accumulator is an extra argument that %%% stores the successive versions of the reversed list as each %%% recursive iteration of reverse occurs. The accumulator makes the %%% list reversal process much more efficient. % :- mode reverse(+,-/+). reverse(List, Rev) :rev(List, [], Rev). rev([], Rev, Rev) :- !. rev([H|T], WorkList, Rev) :rev(T, [H|WorkList], Rev). %%% delete(+Element,+List,-/+NewList) %%% The delete predicate deletes an element from a list and returns %%% the new list. For example: % :- mode delete(+,+,-/+). delete(_,[],[]) :!. delete(X,[X|T],T2) :delete(X,T,T2), !. delete(X,[H|T],[H|T2]) :delete(X,T,T2), !. %%% list_insert(+Element,+List,-/+NewList)

%%% The list_insert predicate inserts an element into a list and %%% returns the new list. The element is placed in the list in sorted %%% order. % :- mode list_insert(+,+,-/+). list_insert(X,[],[X]) :!. list_insert(X,[H|T], [X,H|T]) :compare(<,X,H), !. list_insert(X,[H|T],[H|T2]) :list_insert(X,T,T2), !. %%% writel(+List) %%% The writel predicate writes out the elements of a list %%% consecutively, placing a newline at the end. For example: % :- mode writel(+). writel([]) :!, nl. writel([H|T]) :write(H), writel(T). %%% number_occurrences(+Element,+List,-/+Number)

%%% The number_occurrences predicate indicates the number of %%% occurrences of an element in a list. For example: % :- mode number_occurrences(+,+,-/+). number_occurrences(X, [], 0). number_occurrences(X, [X|T], N1) :!, number_occurrences(X, T, N), inc(N, N1). number_occurrences(X, [_|T], N) :number_occurrences(X, T, N). %%% remove_duplicates(+List,-/+NewList) %%% The remove_duplicates predicate removes all duplicate characters %%% from a list and returns the new list. % :- mode remove_duplicates(+,-/+). remove_duplicates([],[]). remove_duplicates([H|T1], [H|T3]) :delete(H, T1, T2), remove_duplicates(T2, T3). %%% divide(+List,-/+Half1,-/+Half2) %%% The divide predicate divides a list into two halves. A list is %%% divided by placing the first element in Half1, the second element %%% in Half2, the third in Half1, and so on. % :- mode divide(+,-/+,-/+).

divide([], [], []) :- !. divide([A], [A], []) :- !. divide([A,B|T], [A|T1], [B|T2]) :divide(T, T1, T2). %%% %%% END OF LISTS %%%

Bibliografia
[ARI 86] ARITY CORPORATION. The Arity/Prolog Programming language. Arity Corporation, Concord, 1986. [BOR 86] BORLAND INTERNATIONAL. Turbo Prolog - Owner's Handbook.Borland International, Scotts Valley, 1986. [BOR 88] BORLAND INTERNATIONAL. Turbo Prolog - Reference Guide -version 2.0. Borland International, Scotts Valley, 1988. [CLO 84] CLOCKSIN, H. F. & MELLISH, C. S. Programming in Prolog. Spring-Verlag, Berlim, 1984. [COE 88] COELHO, HELDER M. F. & COTTA, J. C. Prolog By Example.SpringerVerlag, Berlim, 1988. [ROY 94] ROY, P. V. 1983-1993: The Wonder Years of Sequential PrologImplementation . The Journal of Logic Programming, v. 19/20, may/july1994.

[YOU 89] YOUNG, R. J. Practical Prolog . Van Nostrand Reinhold,New York, 1989.

Vous aimerez peut-être aussi