¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Soluciones a ejercicios
ejercicios de prolog, 30/03/09
familia
%%%%%%%%%%%% %% HECHOS %% %%%%%%%%%%%% mujer(pepa). mujer(lucía). mujer(blanca). mujer(rosa). mujer(alba). mujer(inés). mujer(irene). hombre(armando). hombre(julián). hombre(esteban). hombre(mario). hombre(alejandro). hombre(martín). hombre(matías). progenitor(pepa,lucía). progenitor(pepa,blanca). progenitor(pepa,mario). progenitor(lucía,rosa). progenitor(lucía,alba). progenitor(blanca,inés). progenitor(blanca,martín). progenitor(irene,matías). progenitor(armando,lucía). progenitor(armando,blanca). progenitor(armando,mario). progenitor(julián,rosa). progenitor(julián,alba). progenitor(alejandro,inés). progenitor(alejandro,martín). progenitor(mario,matías). %%%%%%%%%%%% %% REGLAS %% %%%%%%%%%%%% padre(X,Y) :- hombre(X), progenitor(X,Y). madre(X,Y) :- mujer(X), progenitor(X,Y). hijo(X,Y) :- hombre(X), progenitor(Y,X). hija(X,Y) :- mujer(X), progenitor(Y,X). abuelo(X,Y) :- hombre(X), progenitor(X,Z), progenitor(Z,Y). abuela(X,Y) :- mujer(X), progenitor(X,Z), progenitor(Z,Y). hermano(X,Y) :- hombre(X), progenitor(Z,X), progenitor(Z,Y), not(X=Y). hermana(X,Y) :- mujer(X), progenitor(Z,X), progenitor(Z,Y), not(X=Y). tío(X,Y) :- hermano(X,Z), progenitor(Z,Y). tía(X,Y) :- hermana(X,Z), progenitor(Z,Y). primo(X,Y) :- hijo(X,Z), progenitor(W,Y), ( hermano(Z,W) ; hermana(Z,W) ). prima(X,Y) :- hija(X,Z), progenitor(W,Y), ( hermano(Z,W) ; hermana(Z,W) ). hijoúnico(X) :- not(hermano(_,X) ; hermana(_,X)). % vamos a ver más sobre este problema en la clase
Otra opción para hijo único que funciona mejor, más acorde a nuestras intuiciones sobre el concepto:
hijoúnico(X) :- ( hombre(X) ; mujer(X) ) , ( not(hermano(_,X) ; hermana(_,X)) ).
Esta opción funciona mejor porque el árbol de búsqueda de resultados que se arma y sobre el cual el intérprete hace backtracking es considerablemente distinto.
ejercicios de prolog, 6/04/09
extensión de familia
Incorporamos cuñados, suegras y demás familias políticas. Para ello nos resultará muy útil definir el predicado “pareja”, y podremos escribir el resto de relaciones en función de ella.
pareja(X,Y) :- progenitor(X,Z), progenitor(Y,Z). cuñado(X,Y) :- hermano(X,Z), pareja(Z,Y). cuñada(X,Y) :- hermana(X,Z), pareja(Z,Y). suegra(X,Y) :- madre(X,Z), pareja(Y,Z). suegro(X,Y) :- padre(X,Z), pareja(Y,Z).
Fíjense que no hay que explicitar el sexo del cuñado, suegra, etc. porque ya está implícito en los predicados “hermano” y “madre”, respectivamente.
Para incorporar la regla “hermano mayor”, la única posibilidad es declarar hechos nuevos, en concreto, hechos que nos permitan saber si alguien es mayor o menor que otra persona. Eso se puede hacer más o menos ad hoc: lo más ad hoc que se me ocurre es declarar el hecho mayorQue
entre los pares de hermanos, lo menos ad hoc, declarar la edad de cada persona e inferir de ese dato la relación mayorQue
, de la siguiente manera:
%%% declaramos hechos sobre la edad de algunos miembros de la familia %%% edad(lucía,28). edad(blanca,26). edad(mario,24). mayor(X,Y) :- edad(X,EX), edad(Y,EY), EX>EY. hermanoMayor(X,Y) :- hermano(X,Y), mayor(X,Y). hermanoMenor(X,Y) :- hermano(X,Y), mayor(Y,X). hermanaMayor(X,Y) :- hermana(X,Y), mayor(X,Y). hermanaMenor(X,Y) :- hermana(X,Y), mayor(Y,X).
ejercicios de haskell, 13/04/09
ordena :: (Int,Int) → (Int,Int)
que, dados dos enteros, los ordena de menor a mayor.
ordena :: (Int,Int) -> (Int,Int) ordena (x,y) | x < y = (x,y) | x > y = (y,x) | x == y = (x,y)
ordena' :: (Int,Int) -> (Int,Int) ordena' (x,y) | x <= y = (x,y) | x > y = (y,x)
ambospositivos :: Int → Int → Bool
, que dados dos enteros devuelveTrue
si los dos son positivos.
ambospositivos :: Int -> Int -> Bool ambospositivos x y | x >= 0 && y >= 0 = True | x >= 0 || y < 0 = False
ambospositivos'' :: Int -> Int -> Bool ambospositivos'' x y = x >= 0 && y >= 0
edad :: (Int, Int, Int) → (Int, Int, Int) → Int
que dadas dos fechas indica los años transcurridos entre ellas. Por ejemplo edad (20,10,1968) (30,4,1987) = 18.
edad :: (Int, Int, Int) -> (Int, Int, Int) -> Int edad (diaN,mesN,anioN) (diaA,mesA,anioA) | (mesN < mesA) || (mesN == mesA && diaN < diaA) = (anioA - anioN) - 1 | otherwise = anioA - anioN
cabeza :: [a] –> a
, que devuelve el primer elemento de una lista.
cabeza :: [a] -> a cabeza (x:_) = x cabeza [] = error "la lista es vacía y por lo tanto no tiene cabeza!"
cola :: [a] –> [a]
, que devuelve toda la lista menos el primer elemento.
cola :: [a] -> [a] cola (_:xs) = xs cola [] = []
- Definición del área de un prisma.
area :: Int -> Int -> Int -> Int area alto ancho fondo = 2*frente + 2*lado + 2*tapa where frente = alto * ancho lado = alto * fondo tapa = ancho * fondo
esVaciaOPrimer0 :: [Int] → Bool
que dada una lista decida si es vacía o bien su primer elemento es 0.
esVaciaOPrimer0 :: [Int] -> Bool esVaciaOPrimer0 [] = True esVaciaOPrimer0 (x:_) | x == 0 = True | otherwise = False
esVaciaOPrimer0' :: [Int] -> Bool esVaciaOPrimer0' [] = True esVaciaOPrimer0' (x:_) = x == 0
segundoEsSegundo :: (Int,Int) → [Int] → Bool
que dada una tupla de enteros y una lista de enteros comprueba si el segundo elemento de la tupla es igual al segundo elemento de la lista.
segundoEsSegundo :: (Int,Int) -> [Int] -> Bool segundoEsSegundo (_,x) (_:y:_) = x == y
recortaDia :: [Char] → [Char]
que dada una lista de caracteres, comprueba si las letras de la lista forman el nombre de un día de la semana, si es así, si el día no es del fin de semana, devuelven la primera letra solamente, en cambio, si el día es de fin de semana, devuelven el nombre del día completo. Ayuda: fíjense que el resultado siempre debe ser una lista de caracteres
recortaDia :: [Char] -> [Char] recortaDia x:xs | (x:xs) == "lunes" || (x:xs) == "martes" || (x:xs) == "miercoles" || (x:xs) == "jueves" || (x:xs) == "viernes" = [x] | (x:xs) == "sabado" || (x:xs) == "domingo" = (x:xs) | otherwise = error "el string de entrada no es un dia de la semana o tiene mayusculas o acentos"
ejercicios para seguir pensando y analizando problemas
- ¿Cómo sería un programa para recomendar amigos en una red social tipo facebook?
Algunos de sus compañeros propusieron una solución a este problema, aplicando recursividad. Después del primer parcialito, cuando ya tengan bien asumida la recursividad, vamos a poner en común todo lo que han venido pensando y analizando para ver diferentes formas de encarar este problema.
- ¿Cómo podemos hacer un programa no muy largo que, dado un animal, nos diga si es ovíparo o vivíparo, si vive en la tierra, en el agua o en el aire, si come carne o vegetales, etc.? Traten de usar generalizaciones del tipo
si es mamífero, entonces…
. En esta aproximación, cómo tratarían excepciones como “delfín” o “guppi”?
- Tenemos una lista de las conexiones por tren entre pares de ciudades, por ejemplo
conectadas(Tarragona,Barcelona).
. ¿Cómo sería un programa que nos ayudara a saber si podemos llegar de una ciudad a otra, es decir, si existe una lista de conexiones que nos lleve de una ciudad a otra, o bien eso es imposible? Primero, traten de hacer un programa que nos diga si podemos llegar de una ciudad a otra directamente o bien en dos o en tres pasos…
Para resolver este problema también vamos a hacer un uso intensivo de recursividad.