Aula Prolog 09 - Listas

42
Prolog – 09 Fábio M. Pereira Baseado em Amzi! inc. – www.amzi.com

Transcript of Aula Prolog 09 - Listas

Prolog – 09

Fábio M. Pereira

Baseado emAmzi! inc. – www.amzi.com

Aventura em Prolog 2

Prolog Listas Utilizando Listas Listas X Base de Dados Exercícios

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).

Aventura em Prolog 42

O que vem a seguir?

Operadores Corte ...