Capítulo 3 Lógica de Primeira Ordem Lógica para Programação LEIC - Tagus Park 1 o Semestre, Ano Lectivo 2007/08 c Inês Lynce and Luísa Coheur
Bibliografia Baseados nos slides de Andrew Rice, Universidade de Cambridge, 2007. Martins J.P., Prolog, Capítulo 5. Ben-Ari M., Mathematical Logic for Computer Science, Springer-Verlag, 2003, Capítulo 8. Alguns exercícios de listas foram tirados das folhas de PLF do Prof. Nuno Mamede
Programa de festas Semântica do Prolog Listas em Prolog Aspectos não puros do Prolog Atribuição Corte O Falhanço Forçado A negação Definição de novas operações
Semântica do Prolog Programa em Prolog sequência de cláusulas (e não conjunto!!!!) refutação SLD com: função de selecção que escolhe o primeiro literal numa cláusula objectivo; regra de procura que escolhe a primeira cláusula na sequência de cláusulas que constitui o programa.
Semântica do Prolog Aspectos a considerar semântica declarativa: o que estamos a calcular semântica procedimental: como calcular
Semântica declarativa ant(x, Z) :- ant(x, Y), ad(y, Z). se ant(x, Y) e ad(y, Z) se verificam para uma dada substituição para as variáveis X, Y e Z, então ant(x, Z) tb é verdade para essa substituição das variáveos X e Z.
Semântica procedimental ant(x, Z) :- ant(x, Y), ad(y, Z). para provar ant(x, Z) há que provar primeiro ant(x, Y) e depois, com as substituições adequadas, provar ad(y, Z).
Semântica procedimental do Prolog Para provar um objectivo, percorrem-se as cláusulas do programa pela ordem em que aparecem e tenta-se utilizar cada uma por essa ordem...... unificando o objectivo com a cabeça da cláusula:
Semântica procedimental do Prolog se a unificação falha próxima, ou falhanço se não existem mais cláusulas; se a unificação tem sucesso, aplica-se a substituição resultante da unificação aos literais no corpo da cláusula e resolve-se cada um dos objectivos do corpo da cláusula, da esquerda para a direita (sucesso se todos os objectivos tiveram sucesso, insucesso se um dele falha);
Semântica procedimental do Prolog se falha um dos objectivos, retrocede-se para o objectivo mais recente para o qual ainda pode haver uma solução.
Importância da ordem das cláusulas Prolog segue estratégia de procura em profundidade com retrocesso Pode nunca encontrar solução (mesmo que ela exista) caso siga por um caminho infinito Função de selecção escolhe o primeiro literal do objectivo Regra de procura escolhe a primeira cláusula determinada
Importância da ordem das cláusulas: árvore SLD p(a). p(b). p(c). q(c). : p(x),q(x). : p(x),q(x). : q(a). : q(b). : q(c).
Importância da ordem das cláusulas: exemplo
Vamos lá aos exemplos
E vamos lá voltar às nossas amigas listas
Soma dos elementos de uma lista soma([],0). soma([cabeca Cauda],N) :- soma(cauda,m), N is M+Cabeca.
Remoção de um elemento de uma lista remove(cabeca,[cabeca Cauda],Cauda). remove(x,[cabeca Cauda1],[Cabeca Cauda2]) :- remove(x,cauda1,cauda2).?- remove(el,[1,2,3],res).
?- remove(el,[1,2,3],res).: árvore SLD remove(el,[1,2,3],res). El=1, Res = [2,3]
?- remove(el,[1,2,3],res).: árvore SLD remove(el,[1,2,3],res) El=2, Res = [1,3] remove(el,[2,3],cauda2) El=2, Cauda2 = [3]
?- remove(el,[1,2,3],res).: árvore SLD remove(el,[1,2,3],res) El=3, Res = [1,2] remove(el,[2,3],cauda2) El=3, Cauda2 = [2] remove(el,[3],cauda22) El=3, Cauda22 = []
?- remove(el,[1,2,3],res).: árvore SLD remove(el,[1,2,3],res) No remove(el,[2,3],cauda2) remove(el,[3],cauda22) remove(el,[],cauda23
?- remove(el,[1,2,3],res).: árvore SLD
Comprimento de uma lista (O(N)) Requisitos de memória: O(N) para lista de comprimento N comp1([],0). comp1([ Cauda],N) :- comp1(cauda,m), N is M+1.?- comp1([1,2],x). comp1([1 [2]],X) :- comp1([2],m), X is M+1. comp1([2 []],M) :- comp1([],m1), M is M1+1. comp1([],0). M1 = 0 M is M1+1 M = 1 X is M+1 X = 2 comp1([1,2],2)
Comprimento de uma lista (O(1)) Requisitos de memória: O(1) comp2(lista,res) :- comp2(lista,0,res). comp2([],acum,acum). comp2([ Cauda],Acum,Res) :- Acum1 is Acum+1, comp2(cauda,acum1,res).?- comp2([1,2],x). comp2([1,2],x) :- comp2([1,2],0,x). comp2([1 [2]],0,X) :- Acum1 is 0+1, comp2([2],acum1,x). comp2([2 []],1,X) :- Acum1 is 1+1, comp2([],acum1,x). comp2([],2,2). X=2 comp2([1,2],2)
Comprimento de uma lista: execução
Factorial (versão recursiva) factorial(0, 1). factorial(x, Y) :- X > 0, X1 is X-1, factorial(x1, Z), Y is X * Z.
Factorial (versão recursiva em scheme) (define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1)))))
Permutação de listas perm([],[]). perm(lst,[cabeca Cauda]) :- remove(cabeca,lst,res),perm(res,cauda).
Permutação de listas: exemplo
E vamos lá fazer uns exercícios... Adiciona um elemento ao fim de uma lista Selecciona o n-ésimo elemento de uma lista
Adiciona um elemento ao fim da lista adicionafim(x, [],[X]). adicionafim(x, [Y L], [Y L1]) :- adicionafim(x, L, L1).
Selecciona o n-ésimo elemento de uma lista nth(1, [X L], X). nth(n, [X L], R) :- N > 1, N1 is N-1, nth(n1, L, R).