Mi primer programa en Prolog
Los programas se escriben en ficheros de texto, generalmente con
extension .pl y pueden contener comentarios y código.
Para ello puede utilizar cualquier editor de texto. Le recomendamos
que intente escribir el siguiente programa desde el principio para
familiarizarse con la sintáxis.
% Este es mi primer programa en Prolog
%
% Se trata de un arbol genealogico muy simple
%
%
% Primero defino los parentescos basicos
% de la familia.
% padre(A,B) significa que B es el padre de A...
padre(juan,alberto).
padre(luis,alberto).
padre(alberto,leoncio).
padre(geronimo,leoncio).
padre(luisa,geronimo).
% Ahora defino las condiciones para que
% dos individuos sean hermanos
% hermano(A,B) significa que A es hermano de B...
hermano(A,B) :-
padre(A,P),
padre(B,P),
A \== B.
% Ahora defino el parentesco abuelo-nieto.
% nieto(A,B) significa que A es nieto de B...
nieto(A,B) :-
padre(A,P),
padre(P,B).
Cargando el código
Para compilar y cargar el código existe el predicado
consult/1. Recuerde que puede ser necesario indicar la ruta
completa del fichero fuente. En este ejemplo hemos usado el top-level
shell de SWI-Prolog:
Welcome to SWI-Prolog (Version 2.7.14)
Copyright (c) 1993-1996 University of Amsterdam. All rights
reserved.
For help, use ?- help(Topic). or ?- apropos(Word).
1 ?- consult('arbolgenealogico.pl').
arbolgenealogico.pl compiled, 0.00 sec, 1,108 bytes.
Yes
2 ?-
Predicados reversibles
Una vez que hemos compilado y cargado nuestro programa vamos a
estudiar sus características.
Una de ellas es el backtracking, o la posibilidad de obtener varias
soluciones, como ya hemos visto.
2 ?- hermano(A,B).
A = juan
B = luis ;
A = luis
B = juan ;
A = alberto
B = geronimo ;
A = geronimo
B = alberto ;
No
3 ?-
Ahora vamos a reparar en otra curiosa propiedad que no existe en otros
lenguajes: la reversibilidad. Esto es la habilidad de los
argumentos de los predicados para actuar indistintamente como
argumentos de entrada y/o salida.Por ejemplo:
3 ?- nieto(luis,X).
X = leoncio
No
4 ?-
Aquí, el primer argumento es de entrada mientras que el segundo
es de salida. El predicado nos dice de quién es nieto Luis.
Pero ahora vamos a intercambiar los papeles:
4 ?- nieto(X,leoncio).
X = juan ;
X = luis ;
X = luisa ;
No
5 ?-
Obsérve cómo el mismo predicado que
nos dice el abuelo de un nieto sirve para conocer los nietos de un abuelo.
Estos predicados se dicen reversibles, o que sus argumentos son
reversibles.
Predicados no reversibles
No todos los predicados son reversibles. Por ejemplo, los de
comparación aritmética. El predicado >/2 sirve para
saber si un número es mayor que otro, pero no sirve para saber
todos los números mayores que uno dado (puesto que son
infinitos).
Otros predicados pueden perder la reversibilidad por deseo expreso de
su programador, o solamente ser reversibles para ciertos argumentos
pero no otros. Así podemos hablar de las posibles
formas de invocar un predicado. Esto es lo que se denomina
modos de uso.
Modos de uso
Los modos de uso indican que combinacion de argumentos deben o
no estar instanciados para que un objetivo
tenga sentido.
Se dice que un argumento está instanciado
cuando no es una variable libre.
A efectos de documentación, los modos de uso se describen
con un término anotado en sus argumentos con un símbolo.
Los argumentos pueden ser:
- De entrada y/o salida indistintamente. Estos argumentos se
denotan con un símbolo de interrogación (?).
- De solamente entrada. Estos se denotan con un símbolo
de suma (+).
- De solamente salida. Estos se denotan con un símbolo de
resta (-).
El modo de uso que instancia todos los argumentos siempre es
válido.
Por ejemplo, para el predicado hermano/2 su único modo
de uso es hermano(?A,?B).
Supongamos un predicado cuyos modos de uso son:
- p(+A,+B,-C).
- p(+A,-B,+C).
Entonces son objetivos válidos:
- p(1,2,X).
- p(1,X,3).
- p(1,2,3).
Pero no son válidos:
- p(X,Y,3).
- p(X,2,3).
- p(X,Y,Z).
Los modos de uso se suelen indicar a modo documentativo, pero
actualmente los entornos de desarrollo más avanzados los pueden
utilizar para detectar errores en tiempo de compilación.
Culturilla
- Un compilador que no utiliza los modos de uso no detecta
objetivos inválidos. En ese caso, el programa se ejecuta sin
más. Cuando le llega el turno al objetivo mal formado
pueden ocurrir dos cosas: que el objetivo falle sin más,
o que se lance una excepción. Cualquiera de ellas suele
ir acompañada de un horrendo mensaje por pantalla.
- La forma de describir los modos de uso "formalmente" varia de un
entorno de desarrollo a otro. Si no es posible especificarlos
"formalmente", entonces conviene escribir un comentario
explicativo.
- Si el compilador no detecta modos de uso, es responsabilidad del
programador no invocar objetivos mal formados, tarea que no
resulta nada trivial puesto que hay que saber que variables van
a estar ligadas cuando el programa se ejecute.
- Otra buena práctica es escribir predicados que siempre
sean reversibles.