Entrada e Saída
Prof. Elaine Faria e Hiran Nonato
Programação Lógica
UFU ­ 2012
Créditos
• O material a seguir consiste de adaptações e extensões dos originais gentilmente cedidos pelo Prof. Alexsandro Santos Soares
Arquivos de Dados
• A comunicação com o Prolog até agora foi feita por meio de consultas realizadas pelo usuários que são respondidas através de instanciações de variáveis
• Muitas vezes essa forma de comunicação não é suficientemente adequada
– Entrada de dados na forma de linguagem natural
– Saída em um dado formato desejado
– Entrada e saída para qualquer periférico do computador
Arquivos de Dados
• Existem predicados pré­definidos com o intuito de auxiliar na entrada/saída de dados
– São dependentes da implementação da linguagem Prolog usada
Arquivos de Dados
Luis, A. M. Palazzo, Introdução à Programação Prolog, Educat, 1997.
Arquivos de Dados
• Durante a execução de um programa Prolog dois arquivos estão ativos
– um para entrada  "fonte de entrada corrente"
– um para saída  "fonte de saída corrente “
• No início da execução essas duas fontes correspondem ao terminal do usuário • A fonte de entrada corrente pode ser mudada a qualquer momento para um outro arquivo
see(novoArqEnt).
Arquivo de Entrada
• Exemplo do uso do see
...
see(arq1).
le_do_arquivo(Informacao).
see(user).
...
Arquivos de Saída
• A fonte de saída corrente pode ser mudada – tell(novoArqSai).
• Exemplo do uso do tell
...
tell(arq3).
grava_no_arquivo(Informacao).
tell(user).
...
Arquivos de Dados
• Dois outros predicados devem ser utilizados para fechar os arquivos correntes de entrada e saída respectivamente
– seen/0 e told/0
Abertura de um arquivo
• Pode­se também abrir um fluxo (stream)
…
open(‘arquivo.txt‘, write, Fluxo),
...
close(Fluxo),
…
Abertura de um arquivo
• Para estender um arquivo existente, temos que abrir um fluxo em modo append
…
open(‘arquivo.txt‘, append, Fluxo),
....
close(Fluxo),
...
Arquivos de Dados
• Os arquivos podem ser processados somente na forma sequencial
• A requisição para a leitura irá ocasionar a leitura a partir da posição corrente dessa fonte de entrada • Após a leitura, a posição corrente da fonte de entrada será, o próximo item que ainda não foi lido
• Se uma requisição de leitura é feita para o fim do arquivo  retorna a constante "end_of_file“
• Predicado pre­definido at_end_of_stream(F) usado para verificar se o fim da stream foi atingido
Arquivos de Dados
• A saída de informações ocorre de maneira similar à entrada – A requisição de saída irá adicionar a informação requisitada no final da fonte de saída corrente
Arquivos de Dados
• Há duas maneiras de se utilizar os arquivos em Prolog
– Considerando o caractere como elemento básico do arquivo
– Considerando unidades maiores como elemento básico do arquivo
Arquivos de Dados
• Usando o caractere como elemento básico arquivo
– Predicados: get e put
• Usando unidades maiores como elemento básico do arquivo
– As unidades são os termos Prolog: read e write
• O uso de cada uma dessas modalidades depende do contexto do problema
Processamento de Arquivos de Termos
• read
– Usada para leitura de dados a partir da fonte corrente
read([A],X)
leitura do próximo termo que irá unificar com X
Se X é uma variável então X será instanciada com T
Se a unificação não for possível então o objetivo read(X) irá falhar
Cada termo deve ser seguido por um ponto e um espaço ou enter
A representa o arquivo  não é obrigatório
– É determinístico  não ocorre backtracking
Processamento de Arquivos de Termos
• write
– Fornece a saída de um termo para a fonte corrente
write([A], X)
• tab
– O predicado tab(N) irá ocasionar a saída de N espaços • nl
– O predicado nl(sem argumentos) irá ocasionar o início de uma nova linha
Exemplo 1 ­ Cubo
cubo :­
read(X), processa(X).
processa(fim) :­ !.
processa(N) :­
C is N*N*N,
write(C),
cubo.
?­cubo.
2.
8
5.
25
12.
1728
fim.
true
Exemplo 2 ­ Cubo
cubo :­
write('Próximo valor: '),
read(X),
processa(X).
processa(fim) :­ !.
processa(N) :­
C is N*N*N,
write('O cubo de '), write(N), write('é '),
write(C), nl, cubo.
Dependendo da implementação, uma requisição ("flush/0" para descarregamento dos buffers de I/O) pode ser necessária após o comando de escrita no prompt
Exemplo 3 – Escrevendo Lista
• Procedimento escreveLista(L)
escreveLista([]).
escreveLista([X | L]) :­
write(X), nl, escreveLista(L).
• Procedimento escreveLista2(L)
escreveLista2([]).
escreveLista2([L | LL]) :­
imprime(L), nl, escreveLista2(LL).
imprime([]).
imprime([X | L]) :­
write(X), tab(1), imprime(L).
Exemplo 4
• Programa em Prolog que lê o arquivo (casas.txt) e o exibe na tela.
casas.txt:
grifinoria.
lufa_lufa.
corvinal.
sonserina.
principal:­
open('casas.txt',read,F),
read(F,C1),
read(F,C2), read(F,C3),
read(F,C4),
close(F),
write([C1,C2,C3,C4]), nl.
Exemplo 5
principal:­
open('casas.txt',read,F),
leiaCasas(F,Casas),
close(F),
write(Casas), nl.
leiaCasas(F,[]):­ at_end_of_stream(F).
leiaCasas(F,[X|L]):­ \+ at_end_of_stream(F),
read(F,X), leiaCasas(F, L).
Exemplo 5 com cortes verdes
principal:­
open('casas.txt',read,F),
leiaCasas(F,Casas),
close(F),
write(Casas), nl.
leiaCasas(F,[]):­ at_end_of_stream(F), !.
leiaCasas(F,[X|L]):­ \+ at_end_of_stream(F), !,
read(F,X), leiaCasas(F, L).
Exemplo 6
• Problema
– Arquivo denominado arq1 contendo termos na forma
item(Nro, Descrição, Preço, Fornecedor)
– Deseja­se produzir um outro arquivo que contenha somente os itens fornecidos por um determinado fornecedor
– O nome do fornecedor deve ser escrito no início do arquivo
Exemplo – cont.
principal(NomeForn):­
open('C:\\Entrada.txt',read,AEnt),
open('C:\\Saida.txt',write,ASaida),
write(ASaida, NomeForn),
write(ASaida, '\n'),
leiaForn(AEnt,ASaida, NomeForn),
close(AEnt), close(ASaida).
leiaForn(AEnt,_,_):­
at_end_of_stream(AEnt), !.
leiaForn(AEnt,ASaida,NomeForn):­
read(AEnt,item(Nro,D,P,NomeForn)),!,
write(ASaida, item(Nro,D,P)), write(ASaida,'\n'), leiaForn(AEnt,ASaida,NomeForn).
leiaForn(AEnt,ASaida,NomeForn):­
leiaForn(AEnt,ASaida,NomeForn).
Processamento de caracteres
• Um caractere é escrito na fonte de saída corrente por meio do objetivo
put(C)
C é o código ASCII (um número entre 0 e 255) do caractere a ser escrito – Exemplo
?­put(65), put(66), put(67).
produz a saída:
ABC
Processamento de caracteres
• Um caractere pode ser lido a partir da fonte de entrada corrente por meio do objetivo
get0(C)
ocasiona a leitura do caractere corrente e torna a variável C instanciada com o código ASCII do caractere
Processamento de caracteres
• Leitura de caracteres imprimíveis saltando sobre todos os caracteres não­imprimíveis (espaços em branco)
get(C)
Processamento de caracteres
• O predicado get_code/2 lê o próximo caracter disponível de um fluxo
– Primeiro argumento: um fluxo
– Segundo argumento: o código do caracter
Exemplo usando get_code
leiaPalavra(Fluxo,Palavra):­
get_code(Fluxo,Caracter),
verificaELeiaResto(Caracter,Caracteres,Fluxo),
atom_codes(Palavra,Caracteres). verificaELeiaResto(10, [], _):­ !.
verificaELeiaResto(32, [], _):­ !.
verificaELeiaResto(­1, [], _):­ !. verificaELeiaResto(Caracter,[Caracter|Caracteres],F):­
get_code(F,ProxCaracter),
verificaELeiaResto(ProxCaracter,Caracteres,F).
Conversão de Termos
• Predicado pré­definido atom_codes/2, que relaciona os átomos com o seu código ASCII. – atom_codes(X, L) é verdadeiro, se L é a lista dos códigos dos caracteres em A
– Exemplo
atom_codes(zx232, [122, 120, 50, 51, 50])
Dividindo programas em arquivos
• Muitos predicados Prolog fazem uso dos mesmos predicados básicos
– Por exemplo: member/2, append/3
• É claro que você não quer redefini­los a cada vez que necessitar deles
– Prolog oferece muitos modos de fazer isto
Leitura de programas
• A forma mais simples de dizer ao Prolog para ler as definições de predicados armazenadas em um arquivo é usar os colchetes
?­ [meuArq].
{consulting(meuArq.pl)…}
{meuArq.pl consulted, 233 bytes}
true
?­
Leitura de programas
• Você também pode consultar mais de um arquivo por vez
?­ [meuArq1, meuArq2, meuArq3].
{consulting meuArq1.pl…}
{consulting meuArq2.pl…}
{consulting meuArq3.pl…}
Leitura de programas
• Você não precisa fazer isto interativamente • Ao invés disto, você pode usar uma diretiva na base de dados
:­ [meuArq1, meuArq2].
Leitura de programas
• Talvez, muitos arquivos, independentemente, consultem o mesmo arquivo.
• Verificação extra se as definições dos predicados já são conhecidas: ensure_loaded/1
:­ ensure_loaded([meuArq1, meuArq2]).
Módulos
• Imagine que você está escrevendo um programa que gerencie um banco de dados sobre filmes
• Você projetou dois predicados:
– imprimeAtores/1
– imprimeFilmes/1
• Eles estão armazenados em arquivos diferentes
• Ambos usam um predicado auxiliar:
– exibeLista/1
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
{consulting principal.pl}
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
{consulting principal.pl}
{consulting imprimeAtores.pl}
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
{consulting principal.pl}
{consulting imprimeAtores.pl}
{imprimeAtores.pl consulted}
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
{consulting principal.pl}
{consulting imprimeAtores.pl}
{imprimeAtores.pl consulted}
{consulting imprimeFilmes.pl}
O arquivo principal .pl
% Arquivo principal.pl
:­ [imprimeAtores].
:­ [imprimeFilmes].
?­ [principal].
{consulting principal.pl}
{consulting imprimeAtores.pl}
{imprimeAtores.pl consulted}
{consulting imprimeFilmes.pl}
The procedure exibeLista/1 is being redefined. Old file: imprimeAtores.pl
New file: imprimeFilmes.pl
Do you really want to redefine it?
(y, n, p, or ?)
Usando módulos
• Predicado pré­construído module: – module/1 e module/2
– Para criar um módulo/biblioteca
• Predicado pré­construído use_module: – use_module/1 e use_module/2
– Para importar predicados de uma biblioteca
• Argumentos
– O primeiro argumento é o nome do módulo
– O segundo e opcional argumento é uma lista dos predicados exportados
Nota sobre módulos em Prolog
• Nem todos os interpretadores Prolog possuem este sistema de módulos
• SWI Prolog e Sicstus possuem
• O sistema de módulos do Prolog ainda não é compatível com a norma ISO
O módulo imprimeAtores.pl
% Este é o arquivo: imprimeAtores.pl
:­ module(imprimeAtores,[imprimeAtores/1]).
imprimeAtores(Filme):­
filmesAtor(Ator, Lista),
exibeLista(Lista).
exibeLista([]):­ nl.
exibeLista([X|L]):­
write(X), tab(1), exibeLista(L).
O módulo imprimeFilmes.pl
% Este é o arquivo: imprimeFilmes.pl
:­ module(imprimeFilmes,[imprimeFilmes/1]).
imprimeFilmes(Diretor):­
diretoresFilme(Filme, Lista),
exibeLista(Lista).
exibeLista([]):­ nl.
exibeLista([X|L]):­
write(X), nl, exibeLista(L).
O arquivo revisado principal.pl
• % Este é o arquivo revisado principal.pl
:­ use_module(imprimeAtores).
:­ use_module(imprimeFilmes).
% Este é o arquivo revisado principal.pl
:­ use_module(imprimeAtores,[imprimeAtores/1]).
:­ use_module(imprimeFilmes,[imprimeFilmes/1]).
Bibliotecas
• Muitos dos predicados mais comuns já vem pré­
construídos nos interpretadores Prolog
• Por exemplo, em SWI Prolog, member/2 e append/3 vem como parte de uma biblioteca
• Uma biblioteca é um módulo que define predicados comuns e pode ser carregada usando os predicados normais para importar módulos
Importando bibliotecas
• Ao especificar o nome de uma biblioteca que você quer usar, você pode informar que este módulo é uma biblioteca
• Prolog procurará no lugar certo, ou seja, em um diretório onde todas as bibliotecas estão guardadas
:­ use_module(library(lists)). Referências
• Luis, A. M. Palazzo, Introdução à Programação Prolog, Educat, 1997.
Download

slides - Facom