Entrada/Salida
Streams
Como en todos los lenguajes, en Prolog existe la posibilidad de
manejar entrada/salida, esto es, ficheros, pantalla, impresoras, etc.
Todo ello se hace a través de streams
(concepto idéntico al de otros lenguajes).
Los streams son buffers para escribir y/o leer de dispositivos como el
teclado, la pantalla, el disco, etc. De modo que consideramos tres
tipos de streams:
- Streams de entrada (lectura).
- Streams de salida (escritura).
- Streams de entrada y salida (híbridos).
Existen dos grupos de predicados para manejar streams:
- Aquellos donde el stream se indica explícitamente.
Se suelen utilizar para manipular ficheros y sockets.
- Aquellos donde el stream es ímplicito.
Manipulan la entrada y salida standard, lo que habitualmente
supone el teclado y la pantalla.
Entrada/Salida standard
Cada vez que ejecutamos un programa, éste tiene predefinidos
tres streams correspondientes a la entrada, salida y error standard.
Los siguientes predicados sirven para conocer cuales son dichos
streams:
| Predicado |
Modo de uso |
Descripción |
| current_output/1 |
current_output(-Stream) |
Retorna el stream asociado a la salida standard |
| current_input/1 |
current_input(-Stream) |
Retorna el stream asociado a la entrada standard |
Un programa siempre puede cambiar dichos streams para que se dirijan
a otros dispositivos. El nuevo stream debe obtenerse mediante alguno
de los predicados que veremos más tarde.
| Predicado |
Modo de uso |
Descripción |
| set_output/1 |
set_output(+Stream) |
Cambia el stream asociado a la salida standard |
| set_input/1 |
set_input(+Stream) |
Cambia el stream asociado a la entrada standard |
Entrada standard
El predicado estrella para leer de la entrada standard es
read/1 cuyo modo de uso
es read(-Term).
Dicho predicado es capaz únicamente de leer términos que
estarán separados unos de otros por un
punto (.) y un salto de línea,
igual que cuando tecleamos en el top-level shell.
Cuando ya no hay más términos para leer en la entrada
standard, el predicado retorna el término
end_of_file/0.
Si leer términos no es lo nuestro, simpre podemos leer
caracteres uno a uno mediante el predicado
get/1.
Su modo de uso es get(-Char) y retorna el
código ASCII del caracter leido. Cuando ya no hay
más caracteres retorna -1.
Salida standard
Para escribir en la salida standard disponemos del predicado
write/1 que recibe un término
como argumento.
Análogamente a la entrada standard, el predicado
put/1 escribe caracteres simples,
recibiendo como argumento el codigo ASCII correspondiente.
Adicionalmente existen los predicados
display/1 cuyo
efecto es el mismo que write/1, y el predicado
nl/0 que escribe
un salto de línea en la salida standard.
Ejemplo
Este es un programa que lee números de la entrada standard
(separados por punto) hasta que se encuentra algún
término que no sea un número. Entonces suma todos los
números y escribe el resultado por la salida standard.
sumar_lista([],Parcial,Parcial).
sumar_lista([Num|Resto],Parcial,Result) :-
NParcial is Num+Parcial,
sumar_lista(Resto,NParcial,Result).
leer_numero(Num) :-
read(Num),
number(Num).
suma :-
suma_aux([]).
suma_aux(Lista) :-
leer_numero(Num),
suma_aux([Num|Lista]).
suma_aux(Lista) :-
sumar_lista(Lista,0,Result),
nl,
display('LA SUMA ES : '),
display(Result),
nl.
Entrada/Salida explícita
A diferencia de la entrada/salida standard, estos predicados
podrían no estar predefinidos, en tal caso
deben ser importados previamente.
La biblioteca a importar puede variar de un entorno de desarrollo a
otro, por lo que debe consultar la documentación
correspondiente. El modo de importar bibliotecas también varía
de un sistema a otro.
El predicado read_term/3
Modo de uso: read_term(+Stream,-Termino,+Opciones).
Este predicado sirve para leer términos del stream indicado.
Su peculiaridad radica en que podemos indicar algunas opciones sobre
como leer el término. El argumento Opciones consiste
en una lista (posiblemente vacía) de términos que pueden
ser cualquiera de los siguientes:
- variables(-ListaVariables).
Unifica ListaVariables
con la lista de variables libres que aparecen en el
término leido.
- variable_names(-ListaNombres). Unifica
ListaNombres con una lista de terminos cero-arios que
representan los nombres de las variables libres
que aparecen en el término leido.
- Otras opciones dependen del entorno de desarrollo usado. Consulte
la documentación asociada.
Recuerde que, cuando ocurre el evento de fin de fichero, este
predicado retorna el término
end_of_file/0.
Ejemplo
?- current_input(I),read_term(I,Term,[variables(L1),variable_names(L2)]).
|: t(A,b(C,A)).
I = user_input,
L1 = [_A,_B],
L2 = ['A'=_A,'C'=_B],
Term = t(_A,b(_B,_A)) ?
yes
?-
El predicado write_term/3
Modo de uso: write_term(+Stream,+Termino,+Opciones).
Este predicado es similar al anterior puesto que nos permite escribir
un término en un stream controlando una serie de opciones. El
argumento Opciones debe ser instanciado a una lísta
(posiblemente vacía) de términos que se
encontrarán entre alguno de los siguientes:
- quoted(true). Aquellos functores que
contengan "caracteres raros" (no alfanuméricos) serán
escritos entre comillas simples. Esta opción es muy importante
si los términos van a ser leidos posteriormente con
read_term/3 o similar.
- ignore_ops(true).
Normalmente, aquellos functores
que esten declarados como operadores se escriben de manera infija o
postfija según corresponda. Con esta opción obligamos a que
siempre se escriban de manera prefija. Por ejemplo,
a+b
se escribiría forzosamente como
+(a,b).
- Otras opciones dependen del entorno de desarrollo usado. Consulte
la documentación asociada.
Ejemplo
?- current_output(O),write_term(O,'1 y 2'+Z,[quoted(true),ignore_ops(true)]).
+('1 y 2',_347)
O = user_output ?
yes
?-
Ficheros
Para manipular ficheros solamente necesitamos abrirlos y/o cerrarlos.
Cuando abrimos un fichero obtenemos un stream que podemos manejar
mediante los predicados anteriormente descritos.
Apertura de ficheros
Se hace mediante el predicado open/3,
con el modo de uso
open(+Fichero,+Modo,-Stream).
Fichero es un
término cero-ario con la ruta del fichero (normalmente entre
comillas simples). Modo puede ser uno de estos
términos:
- read/0.
Abrir en modo de solamente lectura.
- write/0.
Abrir en modo de solamente escritura. Si el
fichero contiene datos, se truncan.
- append/0.
Abrir en modo de solamente escritura. El
fichero no se trunca, los nuevos datos se añaden al final.
Cierre de ficheros
Para ello existe el predicado close/1,
cuyo modo de uso
es close(+Stream).
El stream queda invalidado una vez que
se cierra el fichero. Este predicado vuelca a disco los contenidos del
buffer antes de cerrarlo. Si deseamos hacer esto sin cerrar el
fichero, disponemos del predicado
flush_output/1.
Culturilla
- Cuando read/1 intenta leer
un término pero
se encuentra con un error sintáctico (el término
está mal construido), emite un mensaje de error y el
predicado falla. Afortunadamente, hay medios para cambiar este
comportamiento, que veremos más adelante.
- Nada impide que read/1 lea un
término que
contenga variables libres. Tenga en cuenta que
dichas variables serán siempre
distintas a las
variables del programa en ejecución y de las variables
leídas en llamadas anteriores a
read/1,
independientemente del nombre que se les ponga a dichas
variables. Naturalmente, si una variable aparece dos veces en
el mismo término leido, en efecto se tratará de la
misma variable.
- Cuando la entrada standard es el teclado e intentamos leer de él,
Prolog muestra un símbolo de "prompt" para indicarnos que
está preparado para que tecleemos. Dicho símbolo
tiene este curioso aspecto: ¦
© Copyright 2000-2001
Angel Fernández Pineda.