2. Aventura em Prolog 2
Prolog
Listas
Utilizando Listas
Listas X Base de Dados
Exercícios
3. Aventura em Prolog 3
Listas
Lista é uma poderosa estrutura de dados para
manusear e manipular grupos de objetos
Em Prolog, uma lista é simplesmente uma
coleção de termos
Os termos podem ser de qualquer tipo de dado
Prolog, incluindo estruturas e outras listas
Sintaticamente, uma lista é denotada por
colchetes com os termos separados por
vírgulas
Ex: uma lista de objetos da cozinha
[maçã, brócolis, refrigerador]
4. Aventura em Prolog 4
Nani Search
Isto nos dá uma alternativa para representar a
localização dos objetos
Em vez de termos predicados de localização
separados para cada objeto, podemos ter um
predicado de localização por container, com uma
lista de objetos do container
loc_list([maçã, brócolis, biscoito], cozinha).
loc_list([escrivaninha, computador], escritório).
loc_list([lanterna, envelope], escrivaninha).
loc_list([selo, chave], envelope).
loc_list([‘máquina de lavar’], porão).
loc_list([cobertor], ‘máquina de lavar’).
5. Aventura em Prolog 5
Lista Vazia
Existe uma lista especial, chamada lista
vazia, que é representada por um
conjunto de colchetes ([])
Também pode ser referenciada como nil
Pode descrever a falta de conteúdo para
um lugar ou objeto
loc_list([], saguão).
6. Aventura em Prolog 6
Listas X Unificação
Unificação trabalha com listas da
mesma forma que trabalha com outras
estruturas de dados
Com o que sabemos até agora sobre
listas, podemos perguntar
?- loc_list(X, cozinha).
X = [maçã, brócolis, biscoito]
?- [_,X,_] = [maçã, brócolis, biscoito].
X = brócolis
7. Aventura em Prolog 7
Listas X Unificação
Este último exemplo é uma maneira não
prática de retirar elementos de uma
lista
Uma vez que os padrões não unificam a não
ser que ambas as listas possuam o mesmo
número de elementos
Para uma lista ser útil, deve existir uma
maneira fácil de acessar, adicionar e
remover elementos da lista, sem nos
preocupar com o número de elementos
da lista ou com sua ordem
8. Aventura em Prolog 8
Acesso a Elementos da Lista
Duas características de Prolog permitem este
fácil acesso:
Uma notação especial que permite referenciar o
primeiro elemento da lista e o restante dos
elementos da lista
A outra é recursão
Estas duas características nos permite
escrever predicados úteis de listas, como
membro/2, que encontra um membro de uma
lista e anexar/3, que une duas listas
9. Aventura em Prolog 9
Acesso a Elementos da Lista
Todos os predicados de listas seguem uma
estratégia similar
Tentar alguma coisa com o primeiro elemento de
uma lista
Então, recursivamente repetir o processo com o
restante da lista
Notação especial para estruturas de lista:
[X | Y], onde
X é ligada ao primeiro elemento da lista
(cabeça/head)
Y é ligada aos elementos restantes da lista
(calda/tail)
10. Aventura em Prolog 10
Unificação usando Listas
O exemplo seguinte tem unificação bem
sucedida porque as duas estruturas são
sintaticamente equivalentes, note que a calda
é uma lista:
?- [a | [b,c,d]] = [a,b,c,d].
Yes
O próximo exemplo falha por causa do mal
uso do símbolo de barra (|)
O que segue a barra deve ser um termo único, para
ter finalidade prática, deve ser uma lista
O exemplo incorretamente apresenta três termos
após a barra
?- [a | b,c,d] = [a,b,c,d].
No
11. Aventura em Prolog 11
Exemplos
?- [H|T] = [maçã, brócolis, refrigerador].
H = maçã
T = [brócolis, refrigerador]
?- [H|T] = [a, b, c, d, e].
H = a
T = [b, c, d, e]
?- [H|T] = [maçãs, bananas].
H = maçãs
T = [bananas]
?- [H|T] = [a, [b,c,d]].
H = a
T = [[b,c,d]]
12. Aventura em Prolog 12
Exemplos
A calda é uma lista vazia:
?- [H|T] = [maçãs].
H = maçãs
T = []
A lista vazia não unifica com a sintaxe
de listas padrão porque ela não possui
calda
?- [H|T] = [].
No
13. Aventura em Prolog 13
Exemplos
Podemos especificar mais que apenas o
primeiro elemento antes da barra (|)
De fato, a única regra é que deve ser seguida por
uma lista
?- [Um, Dois | T] = [maçã, biscoito, bolo, leite].
Um = maçã
Dois = biscoito
T = [bolo, leite]
?- [X,Y|T] = [a|Z]. ?- [H|T] = [maçã, Z].
X = a H = maçã
Y = _01 T = [_01]
T = _03 Z = _01
Z = [_01 | _03]
Unificação com listas: entendimento
crítico para a construção de
predicados com listas
14. Aventura em Prolog 14
Listas
Uma lista pode ser vista como uma cabeça e
uma lista calda, cuja cabeça é o segundo
elemento e cuja calda é uma lista, cuja cabeça
é o terceiro elemento, e assim por diante
?- [a| [b| [c| [d| []]]]] = [a,b,c,d].
Yes
Dissemos que uma lista é um tipo especial de
estrutura
Em um sentido, ela é, mas em outro ela é apenas
como outro termo Prolog
Se chamarmos a lista de dot/2, então a lista
[a,b,c,d] poderia ser
dot(a, dot(b, dot(c, dot(d, []))))
15. Aventura em Prolog 15
Notação dot
De fato, este predicado existe, pelo menos
conceitualmente, e é chamado de dot, mas é
representado por um ponto (.) em vez de dot
Para vermos a notação de dot, usamos o
predicado interno display/1, que é similar a
write/1, exceto pelo fato de que sempre usa a
sintaxe dot para listas quando escreve na tela
?- X = [a,b,c,d], write(X), nl, display(X), nl.
[a, b, c, d]
.(a, .(b, .(c, .(d, []))))
17. Aventura em Prolog 17
Notação dot
Por que diferentes sintaxes para listas?
A sintaxe mais fácil facilita a leitura, mas
algumas vezes obscurece o comportamento
do predicado
A sintaxe dot ajuda a manter esta estrutura
“real” de listas em mente quando
trabalhando com predicados que manipulam
listas
Esta estrutura de listas é adequada à
escrita de rotinas recursivas
A seguir veremos o predicado membro/2
18. Aventura em Prolog 18
membro/2
Como todo predicado recursivo, iniciaremos
com a condição limite ou caso base
Um elemento é um membro de uma lista se ele é a
cabeça da lista
membro(H, [H|T]).
Esta cláusula ilustra como um fato com argumentos
variáveis age como uma regra
A segunda cláusula de membro/2 é o caso
recursivo
Ele diz que um elemento é membro da lista se é
membro da calda da lista
membro(X, [H|T]):- membro(X,T).
19. Aventura em Prolog 19
membro/2
Note que ambas as cláusulas de membro/2
esperam uma lista como segundo argumento
Uma vez que T em [H|T] na segunda cláusula é ele
mesmo uma lista, a chamada recursiva a membro/2
funciona
?- membro(maçã, [maçã, brócolis, biscoito]).
Yes
?- membro(brócolis, [maçã, brócolis, biscoito]).
Yes
?- membro(banana, [maçã, brócolis, biscoito]).
No
20. Aventura em Prolog 20
membro/2
Utilize trace para acompanhar o
funcionamento do predicado membro/2
membro/2 pode ser usado de várias
maneiras, observe o uso de variáveis e
backtracking
?- membro(X, [maçã, brócolis, biscoito]).
X = maçã ;
X = brócolis ;
X = biscoito ;
No
21. Aventura em Prolog 21
anexar/3
Outro predicado útil de listas:
Constrói listas a partir de outras listas
Alternativamente divide lista em peças
separadas
Neste predicado o segundo argumento é
anexado ao primeiro argumento para
formar o terceiro argumento
Exemplo:
?- anexar([a,b,c], [d,e,f], X).
X = [a,b,c,d,e,f]
22. Aventura em Prolog 22
anexar/3
O funcionamento deste predicado é um pouco
mais difícil de seguir do que membro/2:
A estratégia básica de trabalhar com a cabeça da
lista não é adequada ao problema de adicionar
alguma coisa no fim de uma lista
anexar/3 resolve este problema reduzindo a
primeira lista recursivamente
A condição limite é que uma lista X esteja
anexada a uma lista vazia – o resultado é
também uma lista X
anexar([], X, X).
23. Aventura em Prolog 23
anexar/3
A condição recursiva nos diz que se a
lista X é adicionada à lista [H|T1], então
a cabeça da nova lista é também H, e a
calda da nova lista é o resultado da
inclusão de X à calda da primeira lista:
anexar([H|T1], X, [H|T2]):-
anexar(T1, X, T2).
O predicado completo é:
anexar([], X, X).
anexar([H|T1], X, [H|T2]):-
anexar(T1, X, T2).
24. Aventura em Prolog 24
Exemplos
?- anexar(X, Y, [a,b,c]).
X = []
Y = [a,b,c] ;
X = [a]
Y = [b,c] ;
X = [a,b]
Y = [c] ;
X = [a,b,c]
Y = [] ;
No
25. Aventura em Prolog 25
Utilizando Listas
Agora que possuímos ferramentas para
manipulação de listas, podemos utilizá-las
Por exemplo, se resolvermos usar loc_list/2
em vez de local/2 para armazenar objetos,
podemos escrever um novo local/2 que se
comporte exatamente igual ao anterior, exceto
pelo fato de computar a resposta em vez de
realizar uma busca
Isto ilustrará a linha nebulosa que algumas vezes
existe entre dados e procedimento
O resto do programa não sabe como local/2
consegue seu resultado, se como dado ou por
computação, mas o comportamento é igual até
mesmo no backtracking
26. Aventura em Prolog 26
Nani Search
local/2:
local(X,Y):-
loc_list(Lista, Y), membro(X, Lista).
No jogo, será necessário adicionar objetos às
listas quando algum objeto é deixado em uma
sala
Podemos escrever add_objeto/3, que usa anexar/3
Se os chamarmos de NovoObjeto e Container, ela
nos dará uma NovaLista:
add_objeto(NovoObjeto, Container, NovaLista):-
loc_list(ListaAnterior, Container),
anexar([NovoObjeto], ListaAnterior, NovaLista).
27. Aventura em Prolog 27
Nani Search
Adicionando objetos:
?- add_objeto(ameixa, cozinha, X).
X = [ameixa, maçã, brócolis, biscoito]
Entretanto, este é um caso onde o
mesmo efeito pode ser alcançado
através da unificação e da notação de
listas [Head|Tail]
add_objeto2(NovoObjeto, Container, NovaLista):-
loc_list(ListaAnterior, Container),
NovaLista = [NovoObjeto | ListaAnterior].
28. Aventura em Prolog 28
Nani Search
Testando...
?- add_objeto2(ameixa, cozinha, X).
X = [ameixa, maçã, brócolis, biscoito]
Podemos simplificar um passo, removendo a
unificação explícita e usando a unificação
implícita, que ocorre na cláusula da cabeça
(head), que é a forma preferencial de
construção deste tipo de predicado
add_objeto3(NovoObj, Container, [NovoObj|ListaAnterior]):-
loc_list(ListaAnterior, Container).
29. Aventura em Prolog 29
Nani Search
Funciona da mesma maneira...
?- add_objeto3(ameixa, cozinha, X).
X = [ameixa, maçã, brócolis, biscoito]
Na prática, devemos escrever
deixar_objeto/2 diretamente sem usar o
predicado add_objeto/3 para construir
uma nova lista para nós:
deixar_objeto(Objeto, Lugar):-
retract(loc_list(Lista, Lugar)),
asserta(loc_list([Objeto|Lista], Lugar)).
30. Aventura em Prolog 30
Listas X Base de Dados
Quando você deve usar entradas na base de
dados ou listas para situações, como fizemos
para localização dos objetos, é um questão de
estilo
A sua experiência irá levá-lo a utilizar uma ou outra
em diferentes situações
Algumas vezes, o backtracking sobre múltiplos
predicados é uma solução mais natural para um
problema e outras vezes lidar com recursão sobre
listas é mais natural
Você deve achar que algumas partes de uma
aplicação em particular se enquadram melhor com
múltiplos fatos na base de dados lógica e outras
partes com listas – neste caso é útil saber como
mudar de um formato para o outro
31. Aventura em Prolog 31
Listas X Base de Dados
Converter de uma lista para fatos
múltiplos é simples
Você pode escrever uma rotina que
continuamente adiciona a cabeça da lista
Neste exemplo criamos fatos individuais no
predicado coisas/1
break_out([]).
break_out([Head | Tail]):-
assertz(coisas(Head)),
break_out(Tail).
32. Aventura em Prolog 32
Listas X Base de Dados
Funcionamento:
?- break_out([lápis, biscoito, neve]).
Yes
?- coisas(X).
X = lápis ;
X = biscoito ;
X = neve ;
No
33. Aventura em Prolog 33
Listas X Base de Dados
Transformar múltiplos fatos em uma lista é
mais difícil
Por esta razão, a maioria das versão de Prolog
fornecem predicados internos que fazem este
trabalho
O mais comum é findall/3, cujos argumentos
são
arg1 – Um padrão para os termos na lista resultante
arg2 – Um padrão objetivo
arg3 – A lista resultante
34. Aventura em Prolog 34
Listas X Base de Dados
findall/3 automaticamente faz uma busca por
backtracking completa do padrão objetivo e
armazena cada resultado na lista
Podemos transformar nosso coisas/1 de volta
em uma lista:
?- findall(X, coisas(X), L).
L = [lápis, biscoito, neve]
Padrões interessantes estão disponíveis
Veja como criar uma lista das salas que possuem
conexão com a cozinha:
?- findall(X, conexao(cozinha, X), L).
L = [escritório, porão, ‘sala de jantar’]
35. Aventura em Prolog 35
Listas X Base de Dados
O padrão para o primeiro argumento pode ser
até mesmo mais atrativo e o segundo
argumento pode ser uma conjunção de
objetivos
Parênteses são usados para agrupar a conjunção de
objetivos no segundo argumento, evitando a
ambigüidade em potencial
Aqui findall/3 cria uma lista de estruturas que
localizam os objetos comestíveis
?- findall(alimentoEm(X,Y), (local(X,Y) , comestivel(X)), L).
L = [alimentoEm(maçã, cozinha), alimentoEm(biscoito,
cozinha)]
36. Aventura em Prolog 36
Exercícios
Escreve rotinas de listas que realizem as
seguintes funções:
Remover um elemento dado da lista
Encontrar o elemento após um elemento dado
Dividir a lista em duas listas a partir de um
elemento dado
Retornar o último elemento de uma lista
Contar os elementos de uma lista
Dica: o tamanho de uma lista vazia é zero, o
tamanho de uma lista não vazia é 1 + o tamanho
de sua calda
37. Aventura em Prolog 37
Exercícios
Uma vez que write/1 recebe um único
argumento, múltiplos ‘writes’ são necessários
para imprimir uma mistura de strings de texto
e variáveis
Escreva um predicado de lista respond/1 que recebe
como seu único argumento uma lista de termos a
serem impressos
Este predicado pode ser usado no jogo para
comunicação com o jogador
Exemplo:
respond([‘Você não pode ir para a ’, Sala, ‘ a partir
daqui’])
38. Aventura em Prolog 38
Exercícios
Listas com uma variável na calda são
chamadas listas abertas
Elas possuem algumas propriedades
interessantes
Por exemplo, membro/2 pode ser usado para
adicionar itens a uma lista aberta
Experimente fazer o rastreamento das seguintes
consultas:
?- membro(a,X).
?- membro(b, [a,b,c|X]).
?- membro(d, [a,b,c|X]).
?- ListaAberta = [a,b,c|X], membro(d, ListaAberta),
write(ListaAberta).
40. Aventura em Prolog 40
Exercícios
Banco de dados genealógico
Considere o seguinte programa Prolog:
pais(a1, a2).
pais(a2, a3).
pais(a3, a4).
pais(a4, a5).
ancestral(A, D, [A]):- pais (A,D).
ancestral(A, D, [X|Z]):-
pais(X,D),
ancestral(A, X, Z).
Qual a finalidade do terceiro argumento de
ancestral?
41. Aventura em Prolog 41
Exercícios
Banco de dados genealógico (cont.)
Adivinhe a resposta das seguintes
consultas:
?- ancestral(a2, a3, X).
?- ancestral(a1, a5, X).
?- ancestral(a5, a1, X).
?- ancestral(X, a5, Z).