Vamos a estudiar éste caso:
Ésta solución funciona, pero es conceptualmente errónea:
hermanastros(Hermano1,Hermano2):-
padre(Hermano1,Padre1),
padre(Hermano2,Padre2),
madre(Hermano1,Madre1),
madre(Hermano2,Madre2),
Padre1 is Padre2, %%% Acá está el error
Madre1 \= Madre2.
Si el is sólo sirve para cuentas,
<algo> is Variable.
<algo> is 4.
Si bien funciona, debemos usar las herramientas para lo que corresponde. Cuando una persona lee un is, espera cuentas. Debemos usar las abstracciones que comuniquen correctamente nuestras ideas.
Si las cuentas sólo se hacen con is,
Variable = 5 * 3.
.factorial(N+1,Fac).
(¡Hay una cuenta, y falta un is!)La razón por la que Variable = 5 * 3.
no funciona es que el =
es “tonto”, se fija que a izquierda y a derecha haya exactamente lo mismo. Ver aritmética en prolog.
La razón por la que factorial(N+1,Fac).
no funciona es que la unificación que realiza prolog de valor con variable es igual de “tonta” que el =
. Salvo que yo ponga un is
, no se va a resolver ninguna cuenta.
Entonces:
Resultado is Variable + 1.
(Siempre que Variable
venga unificada).Más abajo la solución certera.
Ésta solución funciona, pero es conceptualmente errónea:
hermanastros(Hermano1,Hermano2):-
padre(Hermano1,Padre1),
padre(Hermano2,Padre2),
madre(Hermano1,Madre1),
madre(Hermano2,Madre2),
Padre1 = Padre2, %%% Acá está el error
Madre1 \= Madre2.
¿Por qué está mal? Porque tiene cierta imperatividad, en donde nosotros estamos forzando a mano que los padres sean iguales, y que las madres sean diferentes.
La idea de verificación que nos ofrece Lógico nos permite representar una igualdad de manera mucho más sencilla, más directa. Sabiendo que Prolog considera cierta una consulta si sus variables matchean, y falsas si no, podemos hacer las cosas más declarativas:
Si el padre es el mismo, entonces, que sea la misma variable. Éste código funciona, y es conceptualmente correcto:
hermanastros(Hermano1,Hermano2):-
padre(Hermano1,Padre), %%% Usamos variable Padre
padre(Hermano2,Padre), %%% Usamos misma variable Padre
madre(Hermano1,Madre1),
madre(Hermano2,Madre2),
Madre1 \= Madre2.
Así se aprovechan mejor las herramientas mencionadas, y redujimos un poco la imperatividad.
Que dos variables tengan el mismo nombre, es una restricción implícita de igualdad
Por otro lado, en el caso de las variables Madre1
y Madre2
, como las variables con nombres diferentes no representan una restricción de diferencia, tenemos que forzar dicha restricción con el \=
.
Tomemos el siguiente problema: “Un instrumento suena lindo si es de cuerda y está afinado”.
Solución:
suenaLindo(Instrumento):-
tipo(Instrumento,Tipo), %%% Pido el tipo
Tipo = cuerda, %%% comparo con cuerda.
estaAfinado(Instrumento).
Eso funciona, pero está conceptualmente mal.
¿Por qué? Veamos:
Eso significa que, en un programa en lógico, los valores de las variables no cambian con el tiempo (una vez unificadas). En nuestro caso, una vez unificado con cuerda
, la variable Tipo
siempre es cuerda
.
Eso significa que, en un programa en lógico, la variable “vale” lo mismo en cualquier parte de la regla. En nuestro caso, al unificarse Tipo
con algún tipo en la 2da línea, eso “llena” la variable automáticamente en la 3era línea. ¡Y no puede cambiar el valor!
En consecuencia, decir Tipo = cuerda
es exactamente lo mismo que escribir cuerda
en todos los lugares donde escribimos Tipo
. La solución correcta:
suenaLindo(Instrumento):-
tipo(Instrumento,`cuerda`),
estaAfinado(Instrumento).
Es muy común ver este tipo de errores en predicados polimórficos y con functores. Ésto funciona, pero está conceptualmente mal:
potencia(Habilidad,Potencia):-
Habilidad = velocista(VelMax),
Potencia = VelMax.
Ésta es la forma correcta:
potencia(velocista(VelMax),VelMax).
El igual es necesario en contados casos. La mayoría de las veces uno se puede arreglar con la metáfora de identidad de lógico, y con un poquito de unificación y pattern matching.
Usemos con criterio las herramientas y conceptos que nos da el paradigma.