PROLOG - Programando com relações
Contato
- Jean Paulo Martins (jeanmartins utfpr edu br)
- Sala 105, Bloco S (UTFPR - Campus Pato Branco)
Conteúdo
Introdução
Programação lógica funciona por meio da definição de relações entre informações. Nesta seção definiremos algumas técnicas para definir relações mais complexas a partir de outras mais simples.
Programando com relações
A forma mais simples de definir uma relação é fornecendo uma lista de fatos. Abaixo listamos alguns fatos sobre usuários de computador: mario, ana, joana; as ferramentas que eles utilizam: compilador, editor, diario, banco de dados, planilha; a arquitetura dos computadores que eles utilizam: sun, pc, mac, e os requisitos de memória de cada aplicação.
usa(mario, compilador, sun).
usa(mario, compilador, pc).
usa(mario, compilador, mac).
usa(mario, editor, sun).
usa(mario, editor, pc).
usa(mario, diario, pc).
usa(ana, editor, mac).
usa(ana, planilha, mac).
usa(joana, bancodados, pc).
usa(joana, compilador, pc).
usa(joana, editor, pc).
requer(compilador, 128).
requer(editor, 512).
requer(planilha, 640).
requer(bancodados, 8192).
Da forma que foram definidos, esses fatos podem ser interpretatos como um banco de dados. Do mesmo modo que em um banco de dados é possível formularmos perguntas sobre as informações armazenadas: query.
Uma possível pergunta seria: “Quais aplicações mario
utiliza num computador sun
?”
uses(mario, X, sun).
Num banco de dados relacional, temos a possibilidade de formular questões por meio da combinação de informações que estão definidas em relações diferentes. Essa característica pode ser simulada em PROLOG.
Escreva um trecho de código PROLOG para representar as seguintes questões:
- “Quais são os requisitos de memória dos programas utilizados no Mac?”
usa(PESSOA, PROGRAMA, mac), requer(PROGRAMA, MEMORIA).
- “Quais os requisitos de memória dos programas que precisam de mais que 256K?”
requer(PROGRAMA, MEMORIA), MEMORIA > 256.
- “Quais os requisitos de memória do editor?”
requer(PROGRAMA, MEMORIA), PROGRAMA = editor. requer(editor, MEMORIA).
- “Quais pessoas usam quais programas em quais máquinas e quanto de memória eles precisam?”
usa(PESSOA, PROGRAMA, MAQUINA), requer(PROGRAMA, MEMORIA).
- “Quais os requisitos de memória dos programas que a Ana usa no mac?”
usa(ana, X, mac), requer(X, Y).
- “Quais programas são usados por pessoas diferentes na mesma máquina?”
usa(PESSOA1, P, M), usa(PESSOA2, P, M), PESSOA1 \= PESSOA2.
- “Quais programas ambas, Ana e Joana, usam?”
usa(ana, P, M1), usa(joana, P, M2).
- “Quais programas ambas, Ana e Joana, usam na mesma máquina?”
usa(ana, P, M), usa(joana, P, M).
- “Quais programas são usados por Ana ou Joana?”
ana_ou_joana(P) :- usa(ana, P, M). ana_ou_joana(P) :- usa(joana, P, M).
- “Quais programas são usados por Ana mas não por Joana?”
usa(ana, P, M1), not(usa(joana, P, M2)).
Estruturas recursivas
Em situações mais realistas os fatos e as relações utilizadas precisam representar informações que posssuam estrutura interna mais ricas do que as vistas na seção anterior. Nesta seção veremos como construir regras capazes de modelar situações com mais que um número fixo de escolhas.
Listas
Uma lista é uma sequência de elementos definida de acordo com a sintaxe
[1,23,5,6].
A definição de regras que utilizam listas como parâmetros aumenta as possibilidades e complexidade das regras. Em geral, operações sobre listas são definidas recursivamente. Por exemplo, suponha que queiramos definir uma regra que diga se um determinado elemento X é ou não um membro da lista.
/* Notação informal */
membro(X, [H|T]) :- X está em [1,23,5,6]?.
A notação [H|T]
indica uma lista qualquer, cujo inicio head
é H
e o restante da lista é referenciado por T
, tail
. Com esse tipo de notação só temos acesso a variáveis $H$ e $T$, não temos acesso a toda lista de uma vez. Exemplo, dada a lista [1,23,5,6]
, H=1
e T=[23,5,6]
.
A seguinte definição recursiva, percorre a lista procurando por uma situação em que $X$ seja o inicio da sublista. Nesta situação teremos que $X$ é membro da lista.
membro(X,[X|T]).
membro(X,[H|T]) :- membro(X, T).
Exercícios
- Escreva um predicado para verificar se um elemento é um membro da lista, ou procurar todos membros da lista. Aplique esse predicado para procurar todos os membros da lista que sejam maior que um determinado inteiro.
member(H, [H,_]).
member(X, [_|T]) :- member(X, T).
- Escreva um predicado para encontrar o último elemento de uma lista.
find_last(X, [X]). find_last(X, [_|T]) :- find_last(X, T).
- Verificar se duas listas são iguais.
equals([],[]). equals([T],[T]). equals([H|T], [I|F]) :- H = I, equals(T, F).
- Escreva um predicado para verificar a existencia de dois elementos consecutivos em uma sequência.
consecutive(X, Y, [X, Y|_]). consecutive(X, Y, [_|T]) :- consecutive(X, Y, T).
- Escreva um predicado para apagar todos elementos de uma lista que sejam igual a um determinado valor.
erase_all(X, [], []). erase_all(X, [H|T], R) :- X = H, erase_all(X, T, R). erase_all(X, [H|T], [H|R]) :- erase_all(X, T, R).
- Utilize os predicados
reverse([H|T], X)
para verificar se uma lista é, ou não, um palindromo.palindrome(L) :- reverse(L, X), equals(L, X).
- Escreva um predicado que ternário
seq(I,F, Sequencia)
, o qual crie a sequência com inteiros deI
aF
seq(F, F, F). seq(I, F, [I|Sequencia]) :- V is I + 1, seq(V, F, Sequencia).
- Máximo
- Comprimento da lista
- Soma da lista
Referências
- MICHAEL SPIVEY. An introduction to logic programming through Prolog. Prentice-Hall, Inc. Upper Saddle River, NJ, USA ©1996 ISBN:0-13-536047-1. PDF