====== Práctica Nro.: 2 (Listas) ======
===== Enunciados =====
- Definir un predicado que permita obtener el último elemento de una Lista.\\
- Definir un predicado que retorne al Cabeza y la Cola de una Lista.\\
- Definir un predicado que calcule la longitud de una Lista.\\
- Definir un predicado verifique si un elemento pertenece o no a una Lista.\\
- Definir un predicado que dadas dos Listas, obtenga la Lista resultante de juntar estas dos en una sola (append).\\
- Definir un predicado que determine si un par de elementos figura en forma adyacente o no en una Lista.\\
- Definir la unión, la intersección, y la diferencia simétrica entre Listas (interpretando a estas como conjuntos).\\
- Con FindAll\\
- Sin FindAll\\
- Definir la relación Disjuntas aplicada a dos Listas.(Dos Listas son disjuntas si no tienen elementos en común)\\
- Con FindAll\\
- Sin FindAll\\
- Definir un predicado que determine la cantidad de hijos que tiene una madre utilizando Listas.\\
- Definir un predicado que obtenga una Lista que contenga la cadena de descendientes entre dos personas.\\
- Definir un predicado que determine la cantidad de hijos varones que tiene una persona.\\
- Definir un predicado que determine todos los hombres que no tienen hijos varones, utilizando Listas.\\
Para los ejercicios 10,11,12 y 13 se debe contar en la base de conocimientos con hechos referentes a las relaciones **Hombre**, **Mujer**, **Padre_de**, etc.
===== Resueltos =====
==== Ej 1 ====
% Ej1 de la Práctica Nro 2.
% Definir un predicado que permita obtener el último elemento de una lista.
domains
elemento = integer
lista = elemento*
predicates
nondeterm obtenerUltimo(lista, elemento).
clauses
% Si es el último elemento le retorno.
obtenerUltimo([Ca|[]], Ultimo) :- Ultimo=Ca.
% Si tiene Cola, no es el último elemento, por eso es que llamo nuevamente obtenerUltimo con la Cola como Lista.
obtenerUltimo([_|Co],Ultimo) :- obtenerUltimo(Co,Ultimo).
goal
obtenerUltimo([], Salida).
==== Ej 2 ====
% Ej 2 de la Práctica Nro 2.
% Definir un predicado que retorne la cabeza y la cola de una Lista
domains
elemento = integer
lista = elemento*
predicates
nondeterm obtenerCabezayCola(lista, elemento, lista).
clauses
obtenerCabezayCola([Ca|Co],Ca,Co).
goal
obtenerCabezayCola([1,2,3,4,5], Cabeza, Cola).
==== Ej 3 ====
% Ej 3 de la Práctica Nro 2.
% Definir un predicado que calcule la longitud de una Lista.
domains
elemento = integer
lista = elemento*
predicates
nondeterm longitud(lista, integer).
clauses
% Si la lista está vacía => Long es igual a 0.
longitud([], Long) :- Long=0.
% Si la lista no esta vacía calculo la longitud de la cola y le sumo uno.
longitud([_|Co],Long) :- longitud(Co,Long2), Long=Long2+1.
goal
longitud([1,2,4,123,5678], Longitud).
==== Ej 4 ====
% Ej 4 de la Práctica Nro 2.
% Definir un predicado que verifique si un elemento pertenece o no a una Lista.
domains
elemento = integer
lista = elemento*
predicates
nondeterm perte(lista, elemento).
clauses
perte([Ca|_], Ca):- !.
perte([Ca|Co], Elem) :- Ca<>Elem, perte(Co, Elem).
goal
perte([1,2,4,123,5678], 2).
==== Ej 5 ====
% Ej 5 de la Práctica Nro 2.
% Definir un predicado que dadas dos Listas, obtenga la Lista resultante de juntar estas dos en una sola (append).
domains
elemento = integer
lista = elemento*
predicates
% Agrego la segunda lista al final de la primera y la retorno en la tercera.
nondeterm append(lista, lista, lista).
clauses
% Si la lista 2 está vacía, la Unión es solo la lista 1.
append(Lista,[], Union) :- Union=Lista, !.
% Si la lista 1 está vacía, la Unión es solo la lista 2.
append([],Lista, Union) :- Union=Lista, !.
append([Ca|Co],L2, Union) :- append(Co,L2,Union2), Union=[Ca|Union2].
goal
append([1,2], [3,4,5], Salida).
==== Ej 6 ====
% Ej 6 de la Práctica Nro 2.
% Definir un predicado que determine si un par de elementos figura en forma adyacente o no en una lisa.
domains
elemento = integer
lista = elemento*
predicates
% Busco si en la primer lista se encuentran adyacentes los elementos de la segunda.
nondeterm buscarAdyasentes(lista, lista, symbol).
nondeterm compararCabezas (lista, lista).
clauses
% Comparo si son iguales las cabezas de las listas.
compararCabezas([Ca1|_],[Ca2|_]) :- Ca1=Ca2.
% Si la lista original esta vacía, sin importar la lista secundaria, el resultado es falso.
buscarAdyasentes([],_,Salida) :- Salida="Falso",!.
% Si la lista secundaria esta vacía, sin importar la lista principal, el resultado es falso.
buscarAdyasentes(_,[],Salida) :- Salida="Falso",!.
% Si las cabezas son distintas, sigo buscando en la cola de la primera.
buscarAdyasentes([Ca1|Co1],[Ca2|Co2],Salida) :- Ca1<>Ca2, buscarAdyasentes(Co1,[Ca2|Co2], Salida).
% Si las cabezas son iguales, pero los dos siguientes no, sigo buscando en la cola del primero.
buscarAdyasentes([Ca1|Co1],[Ca2|Co2],Salida) :- Ca1=Ca2, not (compararCabezas(Co1,Co2)), buscarAdyasentes(Co1,[Ca2|Co2], Salida).
% Si las cabezas son iguales, y los dos siguientes también, entonces esos dos son adyasentes.
buscarAdyasentes([Ca1|Co1],[Ca2|Co2],Salida) :- Ca1=Ca2, compararCabezas(Co1,Co2), Salida="Verdadero",!.
goal
buscarAdyasentes([1,2,3,4,5,1,3,7],[4,5],Resultado).
==== Ej 6 (Otra forma) ====
% Ej 6 de la Práctica Nro 2.
% Definir un predicado que determine si un par de elementos figura en forma adyacente o no en una lisa.
domains
lista = integer*
predicates
nondeterm adyacente(lista, integer, integer).
clauses
adyacente([Ca|Co], E1, E2) :- Ca<>E1, Ca<>E2, adyacente(Co, E1, E2).
adyacente([E1,E2|_], E1, E2).
adyacente([E2,E1|_], E1, E2).
goal
adyacente([1,2,3,1523], 2,3).
==== Ej 7 a ====
% Ej 7.a de la guía 2
% Definir la unión, la intersección, y la diferencia simétrica entre Listas (interpretando a estas como conjuntos) con FindAll.
domains
elemento = integer
lista = elemento*
predicates
nondeterm perte(lista, elemento).
nondeterm perte1AND2(lista, lista, elemento).
nondeterm perte1OR2(lista, lista, elemento).
nondeterm perte1NOT2(lista, lista, elemento).
nondeterm union(lista, lista, lista).
nondeterm inter(lista, lista, lista).
nondeterm diferencia(lista, lista, lista).
clauses
perte([Ca|_],Ca).
perte([_|Co], Elemento) :- perte(Co,Elemento).
perte1AND2(L1, L2, Elemento) :- perte(L1,Elemento), perte(L2,Elemento).
perte1NOT2(L1, L2, Elemento) :- perte(L1,Elemento), not(perte(L2,Elemento)).
perte1OR2(L1, _, Elemento) :- perte(L1,Elemento).
perte1OR2(_, L2, Elemento) :- perte(L2,Elemento).
union(L1,L2,L3) :- findAll(X, perte1OR2(L1,L2,X), L3).
inter(L1,L2,L3) :- findAll(X,perte1AND2(L1,L2,X),L3).
diferencia(L1,L2,L3) :- findAll(X,perte1NOT2(L1,L2,X),L3).
goal
union([1,2,3], [3,5,6], Union),
inter([1,2,3], [3,5,6], Interseccion),
diferencia([1,2,3], [3,5,6], Diferencia).
==== Ej 7 b ====
% Ej 7.b de la guía 2
% Definir la unión, la intersección, y la diferencia simétrica entre Listas (interpretando a estas como conjuntos) sin FindAll.
domains
elemento = integer
lista = elemento*
predicates
nondeterm perte(lista, elemento).
% La segunda lista tendrá como cabeza el elemento y cola la primer lista.
nondeterm insertarElemento(lista, elemento, lista).
nondeterm union(lista, lista, lista).
nondeterm inter(lista, lista, lista).
nondeterm diferencia(lista, lista, lista).
clauses
perte([Ca|_],Ca).
perte([_|Co], Elemento) :- perte(Co,Elemento).
insertarElemento(ListaInicial, Elemento, ListaFinal) :- ListaFinal=[Elemento|ListaInicial].
% Si una de las listas está vacía la unión es toda la otra lista.
union(Lista,[],Lista).
union([],Lista,Lista).
% Lista 1 es de entrada, Lista 2 es de entrada y Lista 3 es de salida.
union([Ca|Co],L2,Union) :- union(Co,L2,Union2), insertarElemento(Union2, Ca, Union).
% Si una de las listas está vacía la intersección es vacía.
inter(_,[],[]).
inter([],_,[]).
% Busco para cada elemento de la lista 1 si pertenece a la lista 2, si es así lo inserto a la lista Intersección.
inter([Ca|Co],L2,Interseccion) :- perte(L2,Ca), inter(Co,L2,Inter2), insertarElemento(Inter2,Ca,Interseccion).
% Si la cabeza no pertenece a la segunda lista, entonces no pertenece a la intersección.
inter([Ca|Co],L2,Interseccion) :- not (perte(L2,Ca)), inter(Co,L2,Interseccion).
% Si la segunda lista está vacía la diferencia es igual a la lista 1.
diferencia (Lista,[], Lista).
% Si la primer lista está vacía, sin importar como es la segunda, la diferencia es vacía.
diferencia ([],_, []).
% Si la Cabeza de la primer lista no está en la segunda, entonces la inserto en diferencia.
diferencia ([Ca|Co], Lista2, Diferencia) :- not (perte(Lista2,Ca)), diferencia(Co,Lista2,Dif2), insertarElemento(Dif2, Ca, Diferencia).
diferencia ([Ca|Co], Lista2, Diferencia) :- perte(Lista2,Ca), diferencia(Co,Lista2,Diferencia).
goal
union([1,2,3], [4,5,6], Union),
inter([1,2,3], [3,5,6], Interseccion),
diferencia([1,2,3], [3,5,6], Diferencia).