Herramientas de usuario

Herramientas del sitio


introalg:taller09_10

Parcial 1 (recuperatorio)

ejercicio 1 (prolog, no recursivo)

  • Dada la siguiente base de conocimiento en prolog, que especifica tres ingredientes necesarios para cocinar un platillo y los que tengo en la casa, crear las reglas necesarias para saber si podremos cocinar un platillo.
ingredientes(tortilla,huevos,aceite,papa).
ingredientes(pizza,prepizza,salsa,queso).
ingredientes(ensalada,lechuga,tomate,aceitunas).
tengo(huevos).
tengo(aceite).
tengo(papa).
Ejemplo: ''puedoCocinar(tortilla). true. puedoCocinar(pizza). false.''
solución
puedoCocinar(X) :- 
   ingredientes(X,A,B,C) ,
   tengo(A) , tengo(B) , tengo(C).

ejercicio 2 (haskell, no recursivo)

  • Definir la función sumaPar :: (Int,Int) → Bool, que, dado un par de enteros, devuelve true si la suma de ambos es par.
Ejemplo: ''sumaPar (2,5) = false.''
solución
sumaPar :: (Int,Int) -> Bool
sumaPar (x,y) = mod (x+y) 2 == 0

ejercicio 3 (recursivo)

  • Definir la función sumaMayoresQueN :: Int → [Int] → Int, que, dado un entero n y una lista de enteros, devuelve la suma de todos los elementos de la lista mayores que n.
Ejemplo: ''sumaMayoresQueN 3 [3,5,2,4] = 9''.
solución
sumaMayoresQueN :: Int -> [Int] -> Int
sumaMayoresQueN n [] = 0
sumaMayoresQueN n (x:xs) | x > n     = x + sumaMayoresQueN n xs
                         | otherwise = sumaMayoresQueN n xs

Parcial 2

ejercicio 1 (usando generalizaciones)

  • Usando map, filter y foldr, definir la función porCientoMayorQue :: Int → Int → [Int] → Int, que dado un número n, otro número m y una lista de enteros, devuelve la suma de todos los porcentajes mayores que n. Ayuda: definir una función auxiliar PorCiento :: Int → Int → Int que use la función div que devuelve la división entera de dos enteros.
Ejemplo: porCientoMayorQue 10 50 [22,4,30,10] = 26.
solución
porCientoMayorQue :: Int -> Int -> [Int] -> Int
porCientoMayorQue n m xs = foldr (+) 0 ( filter (>n) ( map (porCiento m) xs ) )

resolviendo problemas "de la vida real"

  • Definir la parte del sistema de préstamos de una biblioteca que determina si un usuario puede tomar prestado un libro o, si ya está prestado, reservarlo, cumpliendo las siguientes condiciones:
    • un usuario puede tener en préstamo un máximo de seis libros simultáneamente
    • un usuario puede tener un máximo de tres reservas
    • un libro se puede prestar si no está en préstamo ni está reservado por otro usuario

Para plantear el problema, deben definir dos funciones (o predicados) con la siguiente semántica:

puedeTomarPrestado -> usuario -> libro -> Bool
puedeReservar -> usuario -> libro -> Bool

Para plantear el problema en haskell, deben definir las dos funciones principales y la estructura de funciones auxiliares, incluyendo sus signaturas de tipos. Fíjense que eso incluye también definir las estructuras de datos que representarán los libros, los usuarios y cómo se registran los préstamos.

Para plantear el problema en prolog, deben definir los hechos y las reglas. Fíjense que eso incluye definir los predicados para libros, usuarios y préstamos.

Deben plantear el problema en los dos lenguajes, y resolverlo completamente en uno de los dos.

solución

En este problema se pueden plantear muy distintas soluciones, ya que el problema es bien complejo y se puede ver de muchas formas.

Una posible solución en prolog:

%% definimos los usuarios como un predicado con tres argumentos: 
  %% el nombre del usuario (o su identificador si el nombre no alcanza para hacerlos únicos)
  %% el número de libros que tiene en préstamo
  %% el número de libros que tiene reservado
%% dejamos para otra regla la actualización de esos números 
 % cuando alguien toma prestado o reserva un libro

usuario(pepe,6,3).
usuario(maría,5,2).
usuario(carla,6,1).
usuario(esteban,0,0).
usuario(marisol,3,3).

%% definimos los libros como un predicado con tres argumentos:
  %% el título del libro (o su identificador si el nombre no alcanza para hacerlos únicos)
  %% si está prestado o no
  %% si está reservado o no
libro("la isla del tesoro",pres,nores).
libro("el lazarillo de tormes",nopres,nores).
libro("los hombres que no amaban a las mujeres",pres,res).
libro("la chica que soñaba con una cerilla y un bidón de gasolina",nopres,res).

%% después de los hechos, definimos las reglas
puedeTomarPrestado(Usuario,Libro) :-
  usuario(Usuario,Prestados,_),
  libro(Libro,nopres,nores),
  Prestados < 6.

puedeReservar(Usuario,_) :-
  usuario(Usuario,_,Reservados),
  Reservados < 3.

Una posible solución en haskell:

puedeTomarPrestado :: (String,Int,Int) -> (String,Bool,Bool) -> Bool
puedeTomarPrestado (_,lp,_) (_,p,r) = lp < 6 && not(p) && not(r)

puedeReservar :: (String,Int,Int) -> (String,Bool,Bool) -> Bool
puedeReservar (_,_,lr) _ = lr < 3

ejercicio extra (para ayudar a aprobar)

Bonus Track: Definir la función tieneSegmentoOrdenado :: Int → [Int] → Bool, que dado un entero n y una lista de enteros, determina si la lista tiene un segmento de longitud mayor o igual a n cuyos elementos están ordenados de menor a mayor.

Ejemplo: tieneSegmentoOrdenado 3 [5,1,4,11,3,2] = true.
	   tieneSegmentoOrdenado 4 [5,1,4,11,3,2] = false.
solución

Hemos planteado una posible solución que va recorriendo la lista y va contando cuántos elementos encuentra que estén ordenados de menor a mayor. Cuando el número de elementos ordenados alcanza el número de elementos que pedimos que tenga el segmento, la función termina y devuelve True. Cuando encuentra un elemento que es menor al elemento anterior, deja de contar, es decir, pone el contador en 1. Cuando llega a la lista vacía devuelve False.

La función principal es tieneSegmentoOrdenado, que lo único que hace es añadir el argumento contador y pasarle todos los argumentos a la función cuantosOrdenados. La función cuantosOrdenados va comprobando en cada momento si hemos alcanzado la longitud de segmento que estábamos buscando, con la guarda c >= n. Fíjense que si la longitud que buscamos es 0 o 1, nos va a devolver True sin hacer ningún llamado a la función recursiva. Si no, llama a la función recursiva para que recorra la lista y vaya contando la longitud de los segmentos ordenados que encuentra.

La función recursiva es cuentaOrdenado, que va recorriendo la lista. Si encuentra una lista vacía o una lista con un solo elemento, devuelve False, porque llegó al final de la lista sin poder encontrar el segmento que buscaba. Para listas de por lo menos dos elementos, los compara y si el primero es menor que el segundo, entonces suma uno al contador y llama a la función cuantosOrdenados, que comprueba si el segmento que vamos encontrando ya es de la longitud que se pedía en el argumento. Si es así, la función termina con True, si no, vuelve a llamar a cuentaOrdenado. Si el primer elemento es mayor que el segundo, entonces el contador vuelve a su estado inicial, 1, es decir, empieza a contar de nuevo.

tieneSegmentoOrdenado :: Int -> [Int] -> Bool
tieneSegmentoOrdenado n xs = cuantosOrdenados 1 n xs

cuantosOrdenados :: Int -> Int -> [Int] -> Bool
cuantosOrdenados c n xs | c >= n    = True
                        | otherwise = cuentaOrdenado c n xs

cuentaOrdenado :: Int -> Int -> [Int] -> Bool
cuentaOrdenado c n [] = False
cuentaOrdenado c n [x] = False
cuentaOrdenado c n (x:y:xs) | x <= y    = cuantosOrdenados (c+1) n (y:xs)
                            | otherwise = cuentaOrdenado 1 n (y:xs)
introalg/taller09_10.txt · Última modificación: 2018/08/10 03:03 por 127.0.0.1