Buscar..


Observaciones

Se dio vida a una nueva sección llamada Estructuras de datos donde se proporcionan explicaciones de ciertas estructuras + algunos ejemplos simples de creación. Para mantener su contenido conciso y ordenado, no debe contener ninguna documentación sobre la manipulación de datos.

Por lo tanto, esta sección cambió su nombre a "Razonamiento sobre datos" con el propósito de generalizar el razonamiento sobre datos en Prolog. Esto podría incluir temas que van desde la 'inferencia de arriba hacia abajo' hasta 'recorrido de las listas', así como muchos otros. Debido a su amplia generalización, se deben hacer subsecciones claras!

Recursion

Prolog no tiene iteración, pero toda la iteración se puede reescribir usando la recursión. La recursión aparece cuando un predicado contiene un objetivo que se refiere a sí mismo. Al escribir tales predicados en Prolog, un patrón recursivo estándar siempre tiene al menos dos partes:

  • Cláusula base (no recursiva) : por lo general, la (s) regla (s) de caso base representará el ejemplo (s) más pequeño posible del problema que está tratando de resolver: una lista sin miembros, o solo un miembro, o si está trabajando con una estructura de árbol, podría tratar con un árbol vacío o un árbol con un solo nodo, etc. Describe de forma no recursiva la base del proceso recursivo.

  • Cláusula recursiva (continua) : contiene cualquier lógica requerida, incluida una llamada a sí misma, continuando la recursión.

Como ejemplo definiremos el conocido predicado append/3 . Visto de forma declarativa, el append(L1,L2,L3) mantiene cuando la lista L3 es el resultado de las listas adjuntas L1 y L2 . Cuando intentamos averiguar el significado declarativo de un predicado, tratamos de describir las soluciones para las cuales se cumple el predicado. La dificultad radica aquí en tratar de evitar cualquier detalle recurrente paso a paso mientras se sigue teniendo en cuenta el comportamiento procesal que debe mostrar el predicado.

% Base case
append([],L,L).

% Recursive clause
append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).

El caso base declara declarativamente "cualquier L anexada a la lista vacía es L", tenga en cuenta que esto no dice nada acerca de que L esté vacío, o incluso que sea una lista (recuerde, en Prolog todo se reduce a términos):

?- append(X,some_term(a,b),Z).
X = [],
Z = some_term(a, b).

Para describir la regla recursiva, aunque Prolog ejecuta las reglas de izquierda a derecha, omitimos la cabeza por un segundo y miramos el cuerpo primero, leyendo la regla de derecha a izquierda:

    append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).

Ahora decimos que si el cuerpo aguanta: "asumiendo que el append(L1,L2,L3) es válido"

    append([X|L1],L2,[X|L3]) :-  append(L1,L2,L3). 

Entonces también lo hace la cabeza: "entonces también lo append([X|L1],L2,[X|L3]) "

En un lenguaje sencillo, esto simplemente se traduce en:

Suponiendo que L3 es la concatenación de L1 y L2, entonces [X seguido de L3] también es la concatenación de [X seguido de L1] y L2.

En un ejemplo práctico:

"Suponiendo que [1,2,3] es la concatenación de [1] y [2,3], entonces [a, 1,2,3] es también la concatenación de [a, 1] y [2,3]. ”

Ahora veamos algunas consultas:

Siempre es una buena idea probar inicialmente su predicado con la consulta más general en lugar de proporcionarle un caso de prueba de escenario específico. Piénselo: debido a la unificación de Prolog, no estamos obligados a proporcionar datos de prueba, ¡solo le damos variables gratuitas!

?- append(L1,L2,L3).
L1 = [],
L2 = L3 ;                                   % Answer #1
L1 = [_G1162],
L3 = [_G1162|L2] ;                          % Answer #2
L1 = [_G1162, _G1168],
L3 = [_G1162, _G1168|L2] ;                  % Answer #3
L1 = [_G1162, _G1168, _G1174],
L3 = [_G1162, _G1168, _G1174|L2] ;          % Answer #4
...

Reemplazemos la variable libre _G1162 -como la notación con letras alfabéticas para obtener una mejor visión general:

?- append(L1,L2,L3).
L1 = [],
L2 = L3 ;                                   % Answer #1
L1 = [_A],
L3 = [_A|L2] ;                              % Answer #2
L1 = [_A, _B],
L3 = [_A, _B|L2] ;                          % Answer #3
L1 = [_A, _B, _C],
L3 = [_A, _B, _C|L2] ;                      % Answer #4
...

En la primera respuesta, el caso base se ajustó al patrón y Prolog hizo una instancia de L1 a la lista vacía y unificó L2 y L3 lo que demuestra que L3 es la concatenación de la lista vacía y L2.

En la respuesta # 2, a través del retroceso cronológico, la cláusula recursiva entra en juego y Prolog intenta probar que algún elemento en la cabeza de L1 concatenado con L2 es L3 con ese mismo elemento en su lista. Para hacerlo, una nueva variable libre _A está unificada con la cabeza de L1 y se ha demostrado que L3 ahora es [_A|L2] .

Se realiza una nueva llamada recursiva, ahora con L1 = [_A] . Una vez más, Prolog intenta probar que algún elemento colocado en la cabeza de L1 , concatenado con L2 es L3 con ese mismo elemento en su cabeza. Tenga en cuenta que _A ya es el jefe de L1 , que coincide perfectamente con la regla, por lo que ahora, mediante la recursión, Prolog coloca a _A frente a una nueva variable libre y obtenemos L1 = [_A,_B] y L3 = [_A,_B|L2]

Vemos claramente que el patrón recursivo se repite y podemos ver fácilmente que, por ejemplo, el resultado del paso 100 en recursión se vería así:

L1 = [X1,X2,..,X99],
L3 = [X1,X2,..,X99|L2]

Nota: como es típico de un buen código de Prolog, la definición recursiva de append/3 no solo nos brinda la posibilidad de verificar si una lista es la concatenación de otras dos listas, sino que también genera todas las respuestas posibles que satisfacen las relaciones lógicas con cualquiera de ellas. o listas parcialmente instanciadas.

Listas de acceso

Miembro

member/2 tiene un member(?Elem, ?List) firma member(?Elem, ?List) y denota true si Elem es un miembro de List . Este predicado se puede usar para acceder a las variables en una lista, donde se recuperan diferentes soluciones a través del seguimiento.

Consultas de ejemplo:

?- member(X, [1,2,3]).
X = 1 ;
X = 2 ;
X = 3.

?- member(X,[Y]).
X = Y.

?- member(X,Y).
Y = [X|_G969] ;
Y = [_G968, X|_G972] ;
Y = [_G968, _G971, X|_G975] ;
Y = [_G968, _G971, _G974, X|_G978]
...

La coincidencia de patrones

Cuando los índices a los que necesita acceder son pequeños, la coincidencia de patrones puede ser una buena solución, por ejemplo:

third([_,_,X|_], X).
fourth([_,_,_,X|_], X).


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow