Upload
marcos-araujo-antas
View
228
Download
2
Embed Size (px)
Citation preview
Prolog - 1
Prolog
Prolog concretiza o modelo de computação abstracto da Programação em Lógica escolher o golo mais à esquerda na resolvente (em vez da escolha não determinística da cláusula a usar na
próxima redução) pesquisa sequencial das cláusulas em busca de unificação, acompanhada de retrocesso
equivale a uma pesquisa em profundidade da árvore de pesquisa implementável por uma máquina de stack, onde se guardam os
golos da resolvente
Prolog - 2
Paralelismo
outras opções no tratamento do não determinismo percorrer em paralelo todos os ramos da árvore de pesquisa
(paralelismo ou nas várias alternativas de uma cláusula)p q1, q2p q3, q4p q5
executar em paralelo os vários golos de uma resolvente (paralelismo e)
p q1(X), q2(X), q3
Parlog, Concurrent Prolog, GHC
p
q1(X) q3q2(X)e
p
q1, q2 q5q3, q4ou
Prolog - 3
Retrocesso (backtracking) um traço de uma computação pode continuar depois
de uma falha um f seguido a um golo significa golo falhado o golo seguinte é o que seria escolhido pelo mecanismo de
retrocesso corresponde à chamada mais próxima em cujo
procedimento existe uma cláusula alternativa a seguir às cláusulas já usadas o novo golo é idêntico e tem as mesmas variáveis que uma sua
anterior ocorrência no traço, ao mesmo nível ponto de escolha armazenar substituições e estado da resolvente i.e. qual a cláusula
seguinte, para poder regressar
Prolog - 4
Traço com retrocesso
avo( abraao, X )progenitor( abraao, Y ), progenitor( Y,X ) pai( abraao, Y ), progenitor( Y, X )progenitor( isaac, X ) {Y= isaac }pai( isaac, X ) {Y= isaac, X= jacob};progenitor( isaac, X ) {Y= isaac }mae( isaac,X )fprogenitor( abraao, Y ), progenitor( Y,X ) mae( abraao, Y ), progenitor( Y, X )fnão há mais pontos de escolha
Prolog - 5
Ordem das cláusulas determina a ordem por que as soluções são encontradas.
• corresponde a trocar a ordem dos ramos na árvore de pesquisa (como o Prolog escolhe sempre o da esquerda...)
member( X, [X|Xs] ).
member( X, [Z| Xs] ) member( X, Xs ).member( X, [Z| Xs] ) member( X, Xs ).
member( X, [X|Xs] ).
member( X, [1,2,3] ) {X= 1} ;member( X, [1,2,3] )member( X, [2,3] ) {X= 2} ;member( X, [2,3] )member( X, [3] ) {X= 3} ;member( X, [3] )member( X, [] )f
Ordem das cláusulas
member( X, [1,2,3] )member( X, [2,3] )member( X, [3] )member( X, [] )fmember( X, [3] ){X= 3} ;member( X, [2,3] ){X= 2} ;member( X, [ 1,2,3] ){X= 1} ; no
Prolog - 6
Terminação
computação de um golo — cálculo de todas as soluções troca de ordem das cláusulas não altera a árvore de pesquisa; só a
percorre por ordem diferente se existir um ramo infinito a computação nunca termina
não terminação — só com recursão evitar a recursão à esquerda
sao_irmaos( X, Y ) irmao( X, Y ).sao_irmaos( X, Y ) irmao( Y, X ).
a terminação depende também do estado de instanciação dos argumentos — caso do append/3 com o 1º e 3º argumentos listas incompletas, ou member/2, com 2º variável
caso perigoso: recursão à esquerda, golo recursivo é o primeiro no corpo programa
irmao( X, Y ) irmao( Y, X ) traço
irmao( lot, milcah ) irmao( milcah, lot )irmao( lot, milcah )•••
Prolog - 7
antepassado( A, X ) antepassado( Y, X) , progenitor( A, Y ).
antepassado( A, X ) progenitor( A, X ).
Ordem dos golos determina a árvore de pesquisa.
• definição recursiva à esquerda, com ramo infinito — trocar a ordem dos golos
• padrão de instanciação dos argumentos determina a ordem óptima dos golos• objectivo é falhar depressa!
avo( A, N ) progenitor ( Y, N ) , progenitor( A, Y ).
neto( A, N ) progenitor ( A, Y) , progenitor( Y, N ).
Ordem dos golos
pode a ordem dos resultados ser alterada pode a árvore ser de dimensão muito diferente pode a diferença ser existir ou não um ramo infinito
Prolog - 8
Repetições
em muitas situações, convém evitar repetições nas soluções
• minimum( X, Y, X ) X=< Y.• minimum( X, Y, Y ) X>= Y.
minimum( 2, 2, M ) tem duas soluções iguais, M=2 basta corrigir a lógica para evitar a redundância
• minimum( X, Y, Y ) X> Y. noutros casos, é necessário alterar até a semântica do
predicado
Prolog - 9
ideal da PL o Prolog encarregar-se-ia do Controlo deixando aos
utilizadores apenas a Lógica das definições axiomáticas
estas seriam, por assim dizer, directamente executáveis
infelizmente, é necessário conhecer pormenores do modelo de execução do Prolog
Algoritmo = Lógica + Controlo
Equação da PL
Prolog - 10
% factorial( N, F ) F é o n-ésimo factorial
factorial( N, F ) N > 0, N1 is N-1, factorial( N1, F1 ), F is N * F1.
factorial( 0, 1 ).
Aritmética avaliada Objectivo: ter acesso ao processador aritmético da
máquina (eficiência) soma( X, Y, Z ) Z is X + Y X, Y têm que estar instanciados a expressão é avaliada e o resultado colocado em Z
Perde-se: múltiplos usos do predicado (especializa-se para um uso:
soma( X, 2, 5) dá erro) e a estrutura recursiva dos números (não se pode usar
unificação mas sim cálculo explícito)
Prolog - 11
Aritméticos+, -, *, /, modComparação<, =<, >=, =:=, =\=Avaliaçãois
Predicados de sistema Z is 2+4 {Z=6} 4 is 2 + Xerro, se X não for exp aritmética
yes, se X for 2no, se X for inteiro 2
2+4 = 3+3 no X= 5-2 {X= 5-2} unifica 2+4 =:= 3+3 yes avalia 2*3 =< 24/4 yes X \= 8 no não unifica 8 mod 3 \= 2 yes 8 mod 3 =\= 2 no X is X + 3 erro, se X não for exp
aritméticano, cc
7 is 28/4 yes
Prolog - 12
implementação da recursão: cada chamada implica guardar uma estrutura na stack com as variáveis temporárias que podem vir a ser precisas espaço ocupado linear no número de chamadas recursivas
não há construções iterativas, mas há implementações iterativas de programas recursivos quando o golo recursivo é o último do corpo da cláusula, não
há mais pontos de escolha e portanto o espaço ocupado pela chamada anterior pode ser reaproveitado
Iteração
Prolog - 13
Programa iterativo
ao chamar, N e T já não são mais precisos e F é sempre o mesmo, pois só na última chamada recebe o valor no acumulador
trata-se de recursão à direita ou recursão na cauda comparar com factorial/2 atrás, que não tem recursão à direita
% factorial F é o factorial de Nfactorial( N, F ) factorial( N, 1, F ).factorial( N, T, F ) N > 0, T1 is T*N, N1 is N-1,
factorial( N1, T1, F ).factorial( 0, F, F ).
Prolog - 14
Pontos de escolha na variante 1 não se criam pontos de escolha
a unificação do golo com a outra cabeça é impossível, pelo que não há cláusulas alternativas utilizáveis
a criação de um ponto de escolha é pesada: armazenar o ponto da execução, mais o estado de instanciação das variáveis
variante 2: cria ponto de escolha está-se a atrasar a unificação para dentro do corpo da cláusula,
em vez de resolver logo com a unificação na cabeça
Variante 1lista([]).lista([X|Xs]) :- lista( Xs ). Chamada: lista( [1,2,3])
Variante 2lista(Xs) :- Xs = [].lista(X) :- X=[X|Xs], lista( Xs ). Chamada: lista( [1,2,3])
Prolog - 15
Meta-variável em Prolog, tanto os dados como os programas são
representados como termos lógicos é possível manipular os programas como se fossem dados e
vice-versa através do meta-predicado call(X)
• meta-predicado, porque a sua execução é chamar o seu argumento como se fosse um golo [read( G ), call( G ) — lê um termo da entrada e executa-o]
meta-variável — simplificação sintáctica: em vez de call( X ) usar simplesmente X [read( G ), G ]
• definição da disjunção:% X ; Y X ou YX ; Y X.X ; Y Y.
• se, no momento da chamada, a meta-variável estiver por instanciar, dá erro
Prolog - 16
Programa errado
% fib( N, F ) F é o número de Fibonnacci de ordem N
fib( 1, 1 ).fib( 2, 1 ).fib( N, F ) N1 is N-1, N2 is N-2,
fib( N1, F1 ), fib( N2, F2 ), F is F1+F2.
• série: 1 1 2 3 5 8 13 21 34 ...
Prolog - 17
fib( 3, F )
N1 is 3-1, N2 is 3-2, fib( N1, F1 ), fib( N2, F2 ), F is F1+F2
fib( 1, F2 ), F is 1+F2
{F= 2}
F is 1+1
{F2=1}
fib( 2, F1 ), fib( 1, F2 ), F is F1+F2
N1a is 1-1, N2a is 1-2, fib( N1a, F1a ), fib( N2a, F2 a),F2 is F1a+F2a, F is 1+F2
fib( 0, F1a ), fib( -1, F2 a), F2 is F1a+F2a, F is 1+F2
•••
N1b is 2-1, N2b is 2-2, fib( N1b, F1b ), fib( N2b, F2 b),F1 is F1b+F2b, fib( 1, F2 ), F is F1+F2
••• •••
{N1=2, N2=1}
{F1=1}
{N1a=0, N2a=-1}
Programa errado
Prolog - 18
% fib( N, F ) F é o número de Fibonnacci de ordem N
fib( 1, 1 ).fib( 2, 1 ).fib( N, F ) N>2, N1 is N-1, N2 is N-2, fib( N1, F1 ), fib( N2, F2 ), F is F1+F2.guarda
• a guarda funciona como uma espécie de extensão da unificação na cabeça a provocar um retrocesso superficial (logo no 1º golo)
• assim o programa computa só as soluções pretendidas
Solução com guarda
Prolog - 19
fib( 3, F )
3>2, N1 is 3-1, N2 is 3-2, fib( N1, F1 ), fib( N2, F2 ), F is F1+F2
fib( 1, F2 ), F is 1+F2
{F= 2}
F is 1+1
{F2=1}
fib( 2, F1 ), fib( 1, F2 ), F is F1+F2
1>2, N1a is 1-1, N2a is 1-2, fib( N1a, F1a ), fib( N2a, F2 a),F2 is F1a+F2a, F is 1+F2
2>2, N1b is 2-1, N2b is 2-2, fib( N1b, F1b ), fib( N2b, F2 b),F1 is F1b+F2b, fib( 1, F2 ), F is F1+F2
{N1=2, N2=1}
{F1=1}
Solução com guarda
Prolog - 20
Solução com cut
% fib( N, F ) F é o número de Fibonnacci de ordem N
fib( 1, 1 ) !.fib( 2, 1 ) !.fib( N, F ) N1 is N-1, N2 is N-2,
fib( N1, F1 ), fib( N2, F2 ), F is F1+F2.
• fib/2 fica determinista
Prolog - 21
fib( 3, F )
N1 is 3-1, N2 is 3-2, fib( N1, F1 ), fib( N2, F2 ), F is F1+F2
fib( 1, F2 ), F is 1+F2
{F= 2}F is 1+1
{F2=1}
fib( 2, F1 ), fib( 1, F2 ), F is F1+F2
N1a is 1-1, N2a is 1-2, fib( N1a, F1a ), fib( N2a, F2 a), F2 is F1a+F2a, F is 1+F2
fib( 0, F1a ), fib( -1, F2 a), F2 is F1a+F2a, F is 1+F2
•••
N1b is 2-1, N2b is 2-2, fib( N1b, F1b ), fib( N2b, F2 b),F1 is F1b+F2b, fib( 1, F2 ), F is F1+F2
••• •••
{N1=2, N2=1}
{F1=1}
!, fib( 1, F2 ), F is F1+F2
!, F is 1+F2
Solução com cut
Prolog - 22
o cut (!) é um predicado de sistema que expressa determinismo
• se um golo unificou com a cabeça fib( 1, 1 ), não há hipótese de encontrar outra solução, usando outra cláusula
Tratamento do cut — o golo cut sucede e comete o Prolog com todas as escolhas feitas desde que o golo pai unificou com a cláusula onde o cut ocorre.
Cut
o cut corta todas as cláusulas abaixo dele (na definição do mesmo predicado)
o cut corta todas as soluções alternativas dos golos que lhe ficam à esquerda na cláusula
o cut não corta os golos que lhe ficam à direita na cláusula• estes podem produzir várias soluções em retrocesso• retrocesso no cut falha e provoca a escolha da última alternativa
antes da escolha da cláusula que contém o cut
Prolog - 23
Cut verde
cut verde — cut que, se retirado, não afecta as soluções produzidas só serve para evitar ao Prolog o trabalho de percorrer ramos
falhados da árvore de pesquisa [seria o caso de fib/3 com cuts e com a guarda N>2]
problema: a formulação do efeito do cut é muito operacional e destrói, em muitos casos, a declaratividade das definições de predicados só simulando a execução se percebe o comportamento do
programa
Prolog - 24
Predicado determinista
exemplo de cuts verdes — predicado determinista, isto é, em cada caso só uma cláusula é aplicável optimização da recursão na cauda, garantida pondo um cut
antes do último golo, porque deixa de haver pontos de escolha para a computação do golo dessa cláusula
% fusao( Xs, Ys, Zs ) Zs é a lista ordenada com a fusão das listas ordenadas Xs e Ys
fusao( [X|Xs], [Y|Ys], [X|Zs] ) X<Y, !, fusao( Xs, [Y|Ys], Zs ).fusao( [X|Xs], [Y|Ys], [X,Y|Zs] ) X=Y, !, fusao( Xs, Ys, Zs ).fusao( [X|Xs], [Y|Ys], [Y|Zs] ) X>Y, !, fusao( [X|Xs], Ys, Zs ).fusao( Xs, [], Xs ) !.fusao( [], Ys, Ys ) !.
Prolog - 25
Cut vermelho cut vermelho — cut que, se retirado, altera as
soluções produzidas usa-se para implementar (parcialmente) a negação por falha; para eliminar soluções indesejadas [a segunda cláusula de
ordena/2 só se atinge se não se passar pelo cut na primeira]: é perigoso! Basta alterar a ordem das cláusulas para ter resultados errados;
evitar o cálculo de ordenada/1, a negação da condição de cima
% ordena( Xs, Ys ) Ys é a lista ordenada dos elementos de Xsordena( Xs, Ys )
append( As, [X, Y|Bs], Xs ), X>Y, !, append( As, [Y, X|Bs], Xs1 ), ordena( Xs1, Ys ).
ordena( Xs, Xs ). % ordenada( Xs ), !.
Prolog - 26
% nao( X ) não se consegue provar Xnao( X ) X, !, fail.nao( X ).
Implementação da negação
este cut é vermelho (se o retirar, nao(X) sucede sempre) trocar a ordem das cláusulas não se limita a trocar a
ordem das soluções — passa a dar soluções erradas a negação dá resultados inesperados se o golo for
chamado com argumentos não fechados
Prolog - 27
Uso do cut
% estudante_solteiro( X ) ¬ X é estudante e X não é casadoestudante_solteiro( X ) nao( casado(X) ), estudante( X ).estudante( quim ).casado( ze ).
golo estudante_solteiro( X ) falha porque casado( X ) sucede com X=ze, embora X=quim seja uma solução; trocando a ordem já sucede porque chama nao( casado( quim ) ) fechado
Prolog - 28
% minimo( X, Y, Z ) Z é o mínimo entre X e Yminimo( X, Y, Z ) (X=<Y -> Z=X ; Z=Y).
% minimo( X, Y, Z ) Z é o mínimo entre X e Yminimo( X, Y, X ) X=<Y, !.minimo( X, Y, Y ).
Se-então-senão
% P -> Q ; R se P então Q, senão R
P -> Q ; R P, !, Q.
P -> Q ; R R.
este cut é vermelho, porque se baseia na supressão da condição da 2ª cláusula
• P -> Q ; R not P, R.• a vantagem é precisamente evitar a duplicação da avaliação de P