Sobre el uso del igual en prolog

De Uqbar wiki

Descripción del problema

Vamos a estudiar éste caso:

El is sólo se usa para cuentas, las cuentas sólo se hacen con is

É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,

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,

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:

Más abajo la solución certera.

Variable = OtraVariable

É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 \=.

Variable = individuo

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).

Conclusión

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.

Latest update on July 10, 2018 by GitHub