aula prolog 09 - listas
TRANSCRIPT
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]
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 containerloc_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’).
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 objetoloc_list([], saguão).
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
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
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
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)
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
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 = aT = [b, c, d, e]
?- [H|T] = [maçãs, bananas].H = maçãsT = [bananas]
?- [H|T] = [a, [b,c,d]].H = aT = [[b,c,d]]
Aventura em Prolog 12
Exemplos A calda é uma lista vazia:
?- [H|T] = [maçãs].H = maçãsT = []
A lista vazia não unifica com a sintaxe de listas padrão porque ela não possui calda?- [H|T] = [].No
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 = biscoitoT = [bolo, leite]
?- [X,Y|T] = [a|Z]. ?- [H|T] = [maçã, Z].X = a H = maçãY = _01 T = [_01]T = _03 Z = _01Z = [_01 | _03]
Unificação com listas: entendimento crítico para a construção de predicados com listas
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 serdot(a, dot(b, dot(c, dot(d, []))))
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, []))))
Aventura em Prolog 16
Notação dot Exemplos
?- X = [Head|Tail], write(X), nl, display(X), nl.[_01| _02].(_01, _02)
?- X = [a, b, [c, d], e], write(X), nl, display(X), nl.[a, b, [c, d], e].(a, .(b, .(.(c, .(d, [])), .(e, []))))
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
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 listamembro(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 listamembro(X, [H|T]):- membro(X,T).
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
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
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]
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 Xanexar([], X, X).
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).
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
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
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).
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].
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 predicadoadd_objeto3(NovoObj, Container, [NovoObj|ListaAnterior]):- loc_list(ListaAnterior, Container).
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)).
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
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/1break_out([]).break_out([Head | Tail]):-
assertz(coisas(Head)),break_out(Tail).
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
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
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’]
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)]
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
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’])
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).
Aventura em Prolog 39
Exercícios Tente adivinhar o resultado das
consultas:?- [a,b,c,d] = [H|T]. ?- [a,[b,c,d]] = [H|T]. ?- [] = [H|T]. ?- [a] = [H|T]. ?- [maçã,3,X,‘O que?'] = [A,B|Z]. ?- [[a,b,c],[d,e,f],[g,h,i]] = [H|T]. ?- [a(X,c(d,Y)), b(2,3), c(d,Y)] = [H|T].
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?
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).