Entrada e Saída
Prof. Elaine Faria e Hiran Nonato
Programação Lógica
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 computadorArquivos 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
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
Abertura de um arquivo
• Podese 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 predefinido at_end_of_stream(F) usado para verificar se o fim da stream foi atingidoArquivos 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 linhaExemplo 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. trueExemplo 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 promptExemplo 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.
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. grifinoria. lufa_lufa. corvinal. sonserina. casas.txt: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)– Desejase 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: ABCProcessamento 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 caractereProcessamento de caracteres
• Leitura de caracteres imprimíveis saltando sobre
todos os caracteres nãoimprimíveis (espaços em
branco)
Processamento de caracteres
• O predicado get_code/2 lê o próximo caracter
disponível de um fluxo
– Primeiro argumento: um fluxo
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 redefinilos 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
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/1O arquivo principal .pl
% Arquivo principal.pl
: [imprimeAtores]. : [imprimeFilmes].
O arquivo principal .pl
% Arquivo principal.pl
: [imprimeAtores]. : [imprimeFilmes].