Aquí unos ejercicios básicos para empezar a entender Haskell. Con ellos empezamos a conocer sus tipos básicos, la definición de funciones y operadores, el manejo de tuplas, las pruebas con QuickCheck... ¡Importante importar Test.QuickCheck para realizar esto último! (:
{-
-- Ejercicio 1
Tres enteros positivos x, y, z constituyen una terna pitagórica si x^2+y^2=z^2, es decir, si son los lados de un triángulo rectángulo.
a) Define la función
esTerna :: Integer -> Integer -> Integer -> Bool
que compruebe si tres valores forman una terna pitagórica
-}
esTerna :: Integer -> Integer -> Integer -> Bool
esTerna x y z
| (x^2 +y^2 == z^2 )= True
| (x^2 + z^2 == y^2) = True
| (y^2 + z^2 == x^2) = True
| otherwise = False
{-
b) Es fácil demostrar que para cualesquiera x e y enteros positivos con x>y, la terna (x2-y2, 2xy, x2+y2) es pitagórica.
Usando esto, escribe una función terna que tome dos parámetros y devuelva una terna pitagórica
-}
terna :: Integer -> Integer -> (Integer, Integer, Integer)
terna x y= (x^2 - y^2, 2*x*y, x^2 + y^2)
{-
c) Lee y entiende la siguiente propiedad, para comprobar que todas las ternas generadas por la función terna son pitagóricas:
-}
p_ternas x y = x>0 && y>0 && x>y ==> esTerna l1 l2 h
where
(l1,l2,h) = terna x y
{-
--------------------------------------------------------
Ejercicio 2
Define una función polimórfica
intercambia :: (a,b) -> (b,a)
que intercambie de posición los datos de la tupla:
--------------------------------------------------------
-}
intercambia :: (a,b) -> (b,a)
intercambia (x,y) = (y,x)
{-
---------------------------------------------------------
Ejercicio 3
Este ejercicio versa sobre ordenación de tuplas.
---------------------------------------------------------
a) Define una función sobrecargada para tipos con orden
ordena2 :: Ord a => (a,a) -> (a,a)
que tome una tupla con dos valores del mismo tipo y la devuelva ordenada de menor a mayor:
-}
ordena2 :: Ord a => (a,a) -> (a,a)
ordena2 (x,y)
| x > y = (y,x)
| otherwise = (x,y)
p1_ordena2 x y = enOrden (ordena2 (x,y))
where enOrden (x,y) = x<=y
p2_ordena2 x y = mismosElementos (x,y) (ordena2 (x,y))
where
mismosElementos (x,y) (a,b) = (x==a && y==b) || (x==b && y==a)
{-
b) Define una función sobrecargada para tipos con orden
ordena3 :: Ord a => (a,a,a) -> (a,a,a)
que tome una tupla con tres valores del mismo tipo y la devuelva ordenada, con los elementos de menor a mayor:
-}
ordena3 :: Ord a => (a,a,a) -> (a,a,a)
ordena3 (x,y,z)
|x>y = ordena3(y,x,z)
|y>z = ordena3(x,z,y)
|x>z = ordena3(z,x,y)
|otherwise = (x,y,z)
<br />
-- c) Escribe propiedades análogas a las del apartado anterior pero para esta función, y compruébalas usando QuickCheck.
p1_ordena3 x y z = enOrden (ordena3 (x,y,z))
where enOrden (x,y,z) = (x <= y) && (y <= z)
p2_ordena3 x y z = mismosElementos (x,y,z) (ordena3 (x,y,z))
where mismosElementos (x,y,z) (a,b,c) = (x,y,z) == (a,b,c) || (x,y,z) == (a,c,b) || (x,y,z) == (b,a,c) || (x,y,z) == (b,c,a) || (x,y,z) == (c,a,b) || (x,y,z) == (c,b,a)
{-
----------------------------------------------------------
Ejercicio 4.
Aunque ya existe una función predefinida (max :: Ord a => a -> a -> a) para calcular el máximo de dos valores,
el objetivo de este ejercicio es que definas tu propia versión de dicha función.
----------------------------------------------------------
a) Como no está permitido redefinir una función predefinida, define una nueva y llámala max2 :: Ord a => a -> a -> a
-}
max2 :: Ord a => a -> a -> a
max2 x y
| x > y = x
| otherwise = y
--b) Define las siguientes propiedades que debería verificar tu función max2 y compruébalas con QuickCheck
p1_max2 x y = True ==> max2 x y == x || max2 x y == y
p2_max2 x y = True ==> max2 x y >= x || max2 x y >= y
p3_max2 x y = x>=y ==> max2 x y == x
p4_max2 x y = y>=x ==> max2 x y == y
{-
----------------------------------------------------------
Ejercicio 5
Define una función sobrecargada para tipos con orden
entre :: Ord a => a -> (a,a) -> a
que tome un valor x además de una tupla con dos valores (max,min) y compruebe si x pertenece al intervalo determinado por min y max,
devolviendo True o False según corresponda.
----------------------------------------------------------
-}
entre :: Ord a => a -> (a,a) -> Bool
entre x (i1, i2) = x >= i1 && x <= i2
{-
----------------------------------------------------------
Ejercicio 6
Define una función sobrecargada para tipos con igualdad
iguales3 :: Eq a => (a,a,a) -> Bool
que tome una tupla con tres valores del mismo tipo y devuelva True si todos son iguales.
----------------------------------------------------------
-}
iguales3 :: Eq a => (a,a,a) -> Bool
iguales3 (x,y,z) = (x == y && x == z)
{-
---------------------------------------------------------
Ejercicio 7
Recuerda que el cociente y el resto de la división de enteros se corresponde con las funciones predefinidas div y mod.
---------------------------------------------------------
a) Define una función descomponer que, dada una cantidad positiva de segundos, devuelva la descomposición en horas,
minutos y segundos en forma de tupla, de modo que los minutos y segundos de la tupla estén en el rango 0 a 59.
-}
type TotalSegundos = Integer
type Horas = Integer
type Minutos = Integer
type Segundos = Integer
descomponer :: TotalSegundos -> (Horas,Minutos,Segundos)
descomponer x = (horas, minutos, segundos)
where
(horas,resto) = divMod x 3600
(minutos, segundos) = divMod resto 60
--b) Comprueba la corrección de tu función verificando con QuickCheck que cumple la siguiente propiedad:
p_descomponer x = x>=0 ==> h*3600 + m*60 + s == x && entre m (0,59) && entre s (0,59)
where (h,m,s) = descomponer x
-----------------------------------------------------------
-- Ejercicio 8
-----------------------------------------------------------
unEuro :: Double
unEuro = 166.386
-- a) Define una función pesetasAEuros que convierta una cantidad (de tipo Double) de pesetas en los correspondientes euros.
pesetasAEuros :: Double -> Double
pesetasAEuros p = p/unEuro
-- b) b) Define la función eurosAPesetas que convierta euros en pesetas.
eurosAPesetas :: Double -> Double
eurosAPesetas e = e* unEuro
------------------------------------------------------------
-- Ejercicio 9
------------------------------------------------------------
infix 4 ~=
(~=) :: Double -> Double -> Bool
x ~= y = abs (x-y) < epsilon
where epsilon = 1/1000
p_inversas x = eurosAPesetas (pesetasAEuros x) ~= x
{-
-----------------------------------------------------------
-- Ejercicio 10
a) Define una función raíces que tome tres parámetros (correspondientes a los coeficientes a, b y c de la ecuación) y devuelva una
tupla con las dos soluciones reales de la ecuación (para calcular la raíz cuadrada, usa la función predefinida sqrt).
Recuerda que el discriminante se define como b^2-4ac y que la ecuación tiene raíces reales si el discriminante no es negativo.
-----------------------------------------------------------
-}
raíces :: (Ord a, Floating a) => a -> a -> a -> (a, a)
raíces a b c
| dis < 0 = error "Raíces no reales"
| otherwise = ((-b + raizDisc) / denominador, (-b - raizDisc) / denominador)
where dis = b^2 - 4*a*c
raizDisc = sqrt dis
denominador = 2*a
p2_raíces a b c = a/= 0 && b^2 - 4*a*c >= 0 ==> esRaíz r1 && esRaíz r2
where
(r1,r2) = raíces a b c
esRaíz r = a*r^2 + b*r + c ~= 0
------------------------------------------------------------
-- Ejercicio 11
-- Define una función esMúltiplo sobrecargada para tipos integrales que tome dos valores x e y, y devuelva True si x es múltiplo de y.
-------------------------------------------------------------
esMúltiplo :: Integer -> Integer -> Bool
esMúltiplo x y = (mod x y == 0)
------------------------------------------------------------
-- Ejercicio 12
-- Define el operador de implicación lógica (==>>) :: Bool -> Bool -> Bool de forma que sea asociativo a la izquierda,
--con precedencia menor que los operadores conjunción y disyunción
------------------------------------------------------------
infixl 1 ==>>
(==>>) :: Bool -> Bool -> Bool
False ==>> y = True
True ==>> y = y
{-
------------------------------------------------------------
-- Ejercicio 13
Los años bisiestos son los años múltiplos de 4. Una excepción a esta regla son los años múltiplos de 100, que sólo se consideran bisiestos
si además son múltiplos de 400. Define una función esBisiesto que tome como parámetro un año y devuelva True si es bisiesto.
------------------------------------------------------------
Ayuda: utiliza el operador de implicación lógica y la siguiente frase: “n es bisiesto si satisface las dos condiciones siguientes:
(a) es múltiplo de 4, y (b) si n es múltiplo de 100 entonces n es múltiplo de 400”.
-}
esBisiesto :: Integer -> Bool
esBisiesto x
| (mod x 4 == 0) && ((mod x 100==0) ==>> (mod x 400 == 0)) = True
| otherwise = False
{-
------------------------------------------------------------
Ejercicio 14
Aunque ya existe en Haskell el operador predefinido (^) para calcular potencias, el objetivo de este problema es que definas
tus propias versiones recursiva de este operador.
------------------------------------------------------------
a) A partir de la propiedad b^n = b·b^(n-1) define una función recursiva potencia que tome un entero b y un exponente natural n y devuelva b^n.
-}
potencia :: Integer -> Integer -> Integer
potencia x n
| n == 0 = 1
| n > 0 = x * potencia x (n-1)
| otherwise = error "Exponente negativo"
-- b)
potencia' :: Integer -> Integer -> Integer
potencia' x n
| n == 0 = 1
| even n = potencia' x (div n 2) * potencia' x (div n 2)
| otherwise = x * potencia' x (div (n-1) 2) * potencia' x (div (n-1) 2)
-- c) Comprueba con QuickCheck la corrección de ambas funciones mediante la siguiente propiedad
p_pot b n = n>=0 ==> potencia b n == sol && potencia' b n == sol
where sol = b^n
{-
--------------------------------------------------------------
-- Ejercicio 15
Dado un conjunto finito con todos sus elementos diferentes, llamamos permutación a cada una de las posibles ordenaciones de los
elementos de dicho conjunto. Por ejemplo, para el conjunto {1,2,3}, existen un total de 6 permutaciones de sus elementos:
{1,2,3}, {1,3,2}, {2,1,3}, {2,3,1}, {3,1,2} y {3,2,1}. El número de permutaciones posibles para un conjunto con n elementos
viene dada por el factorial de n (se suele escribir n!), que se define como el producto de todos los números naturales menores
o iguales a n. Escribe una función factorial que tome como parámetro un número natural y devuelva su factorial.
Dado que el factorial crece muy rápido, usa el tipo Integer, es decir, factorial :: Integer -> Integer.
--------------------------------------------------------------
-}
factorial :: Integer -> Integer
factorial 1 = 1
factorial n = n* factorial(n-1)
--------------------------------------------------------------
-- Ejercicio 16 -- FALTA APARTADO C
-- Este ejercicio estudia la división entera (exacta) de números enteros.
--------------------------------------------------------------
{-
a) Define una función divideA que compruebe si su primer argumento divide exactamente al segundo.
-}
divideA :: Integer -> Integer -> Bool
divideA a b = (mod b a == 0)
-- b)
p1_divideA x y = y/=0 && y `divideA` x ==> div x y * y == x
-- c) Escribe una propiedad p2_divideA para comprobar usando QuickCheck que si un número divide a otros dos, también divide a la suma de ambos.
p2_divideA a b c = a /= 0 && divideA a b && divideA a c ==> divideA a (b+c)
{-
-------------------------------------------------------------
-- Ejercicio 17
La mediana de un conjunto de valores es aquel valor tal que el 50% de los valores del conjunto son menores o iguales a él, y los restantes mayores o iguales.
Queremos definir una función para calcular la mediana de los valores de una tupla de cinco elementos
mediana :: Ord a => (a,a,a,a,a) -> a
de forma que se tenga: mediana (3,20,1,10,50) 10
Observa que se satisface 1 , 3 ≤ 10 ≤ 20,50. Teniendo en cuenta este detalle, define la función a través de ecuaciones con guardas:
-------------------------------------------------------------
-}
mediana :: Ord a =>; (a,a,a,a,a) -> a
mediana (x,y,z,t,u)
| x > z = mediana (z,y,x,t,u)
| y > z = mediana (x,z,y,t,u)
| t < z = mediana (x, y, t, z, u)
| u < z = mediana (x, y, u, t ,z)
| otherwise = z
Blog dedicado a aquellas personas que quieren aprender a programar, a las que quieren mejorar y a las que quieren repasar. Este blog no pretende ser una guía a seguir. No voy a dar clases ni a enseñar a instalar el IDE, sino que se centrará en resolver ejercicios. El blog está algo descuidado por falta de tiempo, pero no dudeis en pedir ayuda o preguntar cosas en los post. aprendiendoaprogramarentretodo@gmail.com
Suscribirse a:
Enviar comentarios (Atom)
No hay comentarios:
Publicar un comentario