Acciones

Relación 2

De Informática de 1º de Matemáticas [Curso 2021-22, Grupo 2]

Revisión del 22:14 5 oct 2021 de Mdelamor (discusión | contribs.) (Página creada con «<source lang='haskell'> -- I1M 2021-22: Rel_2.hs (08 de octubre de 2021) -- Definiciones con condicionales, guardas o patrones. -- Departamento de Ciencias de la Computaci…»)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)
-- I1M 2021-22: Rel_2.hs (08 de octubre de 2021)
-- Definiciones con condicionales, guardas o patrones.
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

-- ---------------------------------------------------------------------
-- Introducción                                                       --
-- ---------------------------------------------------------------------

-- En esta relación se presentan ejercicios con definiciones elementales
-- (no recursivas) de funciones que usan condicionales, guardas o
-- patrones. 
--
-- De forma adicional, se adjuntan ejercicios de repaso para trabajar con
-- operaciones lógicas sobre valores de verdad (o booleanos), sobre todo
-- con &&, || y not. 
-- 
-- Estos ejercicios se corresponden con el tema 4 cuyas transparencias
-- se encuentran en  
--    http://www.cs.us.es/~jalonso/cursos/i1m/temas/tema-4.html

-- ---------------------------------------------------------------------
-- § Librerías auxiliares                                             --
-- ---------------------------------------------------------------------

-- Esta librería se puede instalar de la siguiente forma:
-- 1. Abrir cmd (Windows) o Terminal (MacOS y Linux)
-- 2. Escribir: cabal update
-- 3. Escribir: cabal install QuickCheck

import Test.QuickCheck

-- ---------------------------------------------------------------------
-- Ejercicio 1. Definir la función 
--    divisionSegura :: Double -> Double -> Double
-- tal que (divisionSegura x y) es x/y si y no es cero y 9999 en caso
-- contrario. Por ejemplo,
--    divisionSegura 7 2  ==  3.5
--    divisionSegura 7 0  ==  9999.0
-- ---------------------------------------------------------------------

divisionSegura :: Double -> Double -> Double
divisionSegura = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 2. Definir la función 
--    intercambia :: (a,b) -> (b,a)
-- tal que (intercambia p)  es el punto obtenido intercambiando las
-- coordenadas del punto p. Por ejemplo, 
--    intercambia (2,5)  ==  (5,2)
--    intercambia (5,2)  ==  (2,5)
-- ---------------------------------------------------------------------

intercambia :: (a,b) -> (b,a)
intercambia = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 3. Comprobar con QuickCheck que la función intercambia es
-- idempotente; es decir, si se aplica dos veces es lo mismo que no
-- aplicarla ninguna.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_intercambia :: (Int,Int) -> Bool
prop_intercambia = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 4.1. Definir una función 
--    ciclo :: [a] -> [a]
-- tal que (ciclo xs) es la lista obtenida permutando cíclicamente los
-- elementos de la lista xs, pasando el último elemento al principio de
-- la lista. Por ejemplo, 
--    ciclo [2,5,7,9]  == [9,2,5,7]
--    ciclo []         == []
--    ciclo [2]        == [2]
-- ---------------------------------------------------------------------

ciclo :: [a] -> [a]
ciclo = undefined 

-- ---------------------------------------------------------------------
-- Ejercicio 4.2. Comprobar que la longitud es un invariante de la
-- función ciclo; es decir, la longitud de (ciclo xs) es la misma que la
-- de xs.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_ciclo :: [Int] -> Bool 
prop_ciclo xs = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 5. Definir la función 
--    numeroMayor :: (Num a, Ord a) => a -> a -> a
-- tal que (numeroMayor x y) es el mayor número de dos cifras que puede
-- construirse con los dígitos x e y. Por ejemplo,  
--    numeroMayor 2 5 ==  52
--    numeroMayor 5 2 ==  52
-- ---------------------------------------------------------------------

numeroMayor :: (Num a, Ord a) => a -> a -> a
numeroMayor x y = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 6. Definir la función 
--    numeroDeRaices :: (Num t, Ord t) => t -> t -> t -> Int
-- tal que (numeroDeRaices a b c) es el número de raíces reales de la
-- ecuación a*x^2 + b*x + c = 0. Por ejemplo,
--    numeroDeRaices 2 0 3    ==  0
--    numeroDeRaices 4 4 1    ==  1
--    numeroDeRaices 5 23 12  ==  2
-- ---------------------------------------------------------------------

numeroDeRaices :: (Num t, Ord t) => t -> t -> t -> Int
numeroDeRaices a b c = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 7. Definir la función 
--    raices :: Double -> Double -> Double -> [Double]
-- tal que (raices a b c) es la lista de las raíces reales de la
-- ecuación ax^2 + bx + c = 0. Por ejemplo, 
--    raices 1 3 2    ==  [-1.0,-2.0]
--    raices 1 (-2) 1 ==  [1.0,1.0]
--    raices 1 0 1    ==  []
-- ---------------------------------------------------------------------

raices :: Double -> Double -> Double -> [Double]
raices a b c = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 8. Definir el operador
--    (~=) :: (Fractional a, Ord a) => a -> a -> Bool
-- tal que (x ~= y) se verifica si x e y son casi iguales; es decir si
-- el valor absoluto de su diferencia es menor que una milésima. Por
-- ejemplo, 
--    12.3457 ~= 12.3459  ==  True
--    12.3457 ~= 12.3479  ==  False
-- ---------------------------------------------------------------------

(~=) :: (Fractional a, Ord a) => a -> a -> Bool
x ~= y = undefined

-- --------------------------------------------------------------------- 
-- Ejercicio 9. Comprobar con QuickCheck que la suma de las raíces
-- de la ecuación ax^2 + bx + c = 0 (con a no nulo) es -b/a y su
-- producto es c/a.
--
-- Nota. En la comparación usar ~= en lugar de ==
-- ---------------------------------------------------------------------

-- La propiedad es
prop_raices :: Double -> Double -> Double -> Property
prop_raices a b c = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 10. En geometría, la fórmula de Herón, descubierta por
-- Herón de Alejandría, dice que el área de un triángulo cuyo lados
-- miden a, b y c es la raíz cuadrada de s(s-a)(s-b)(s-c) donde s es el
-- semiperímetro 
--    s = (a+b+c)/2
-- 
-- Definir la función 
--    area :: Double -> Double -> Double -> Double 
-- tal que (area a b c) es el área del triángulo de lados a, b y c. Por
-- ejemplo, 
--    area 3 4 5  ==  6.0
-- ---------------------------------------------------------------------

area :: Double -> Double -> Double -> Double 
area a b c = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 11. Los intervalos cerrados se pueden representar mediante
-- una lista de dos números (el primero es el extremo inferior del
-- intervalo y el segundo el superior). 
-- 
-- Definir la función 
--    interseccion :: Ord a => [a] -> [a] -> [a]
-- tal que (interseccion i1 i2) es la intersección de los intervalos i1 e
-- i2. Por ejemplo,
--    interseccion [] [3,5]     ==  []
--    interseccion [3,5] []     ==  []
--    interseccion [2,4] [6,9]  ==  []
--    interseccion [2,6] [6,9]  ==  [6,6]
--    interseccion [2,6] [0,9]  ==  [2,6]
--    interseccion [2,6] [0,4]  ==  [2,4]
--    interseccion [4,6] [0,4]  ==  [4,4]
--    interseccion [5,6] [0,4]  ==  []
-- ---------------------------------------------------------------------

interseccion :: Ord a => [a] -> [a] -> [a]
interseccion = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 12. Comprobar con QuickCheck que la intersección de
-- intervalos es conmutativa.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_interseccion :: Int -> Int -> Int -> Int -> Bool
prop_interseccion a1 b1 a2 b2 = undefined

-- La comprobación es


-- ---------------------------------------------------------------------
-- Ejercicio 13.1. Los números racionales pueden representarse mediante
-- pares de números enteros. Por ejemplo, el número 2/5 puede
-- representarse mediante el par (2,5). 
-- 
-- Definir la función 
--    formaReducida :: (Int,Int) -> (Int,Int) 
-- tal que (formaReducida x) es la forma reducida del número racional
-- x. Por ejemplo, 
--    formaReducida (4,10)  ==  (2,5)
-- ---------------------------------------------------------------------

formaReducida :: (Int,Int) -> (Int,Int) 
formaReducida (a,b) = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 13.2. Definir la función 
--    sumaRacional :: (Int,Int) -> (Int,Int) -> (Int,Int)
-- tal que (sumaRacional x y) es la suma de los números racionales x e
-- y, expresada en forma reducida. Por ejemplo, 
--    sumaRacional (2,3) (5,6)  ==  (3,2)
-- ---------------------------------------------------------------------

sumaRacional :: (Int,Int) -> (Int,Int) -> (Int,Int)
sumaRacional (a,b) (c,d) = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 13.3. Definir la función 
--    productoRacional :: (Int,Int) -> (Int,Int) -> (Int,Int)
-- tal que (productoRacional x y) es el producto de los números
-- racionales x e y. Por ejemplo, 
--    productoRacional (2,3) (5,6)  ==  (5,9)
-- ---------------------------------------------------------------------

productoRacional :: (Int,Int) -> (Int,Int) -> (Int,Int)
productoRacional (a,b) (c,d) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 13.4. Definir la función
--    cocienteRacional ::  (Int,Int) -> (Int,Int) -> (Int,Int)
-- tal que '(cocienteRacional x y)' es el cociente de los números racionales
-- 'x' e 'y'. Por ejemplo,
--    cocienteRacional (2,3) (5,6)  ==  (4,5)
-- ----------------------------------------------------------------------------

cocienteRacional ::  (Int,Int) -> (Int,Int) -> (Int,Int)
cocienteRacional (x1,x2) (y1,y2) = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 13.5. Definir la función 
--    igualdadRacional :: (Int,Int) -> (Int,Int) -> Bool
-- tal que (igualdadRacional x y) se verifica si los números racionales
-- x e y son iguales. Por ejemplo, 
--    igualdadRacional (6,9) (10,15)  ==  True
--    igualdadRacional (6,9) (11,15)  ==  False
--    igualdadRacional (0,2) (0,-5)   ==  True
-- ---------------------------------------------------------------------

igualdadRacional :: (Int,Int) -> (Int,Int) -> Bool
igualdadRacional (a,b) (c,d) = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 13.6. Comprobar con QuickCheck la propiedad distributiva
-- del producto racional respecto de la suma.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_distributiva :: (Int,Int) -> (Int,Int) -> (Int,Int) -> Property
prop_distributiva x y z = undefined

-- La comprobación es

-- ----------------------------------------------------------------------------
-- Ejercicio 14. Los números complejos se pueden representar mediante pares de 
-- números reales. Por ejemplo, el número 2+5i se puede representar mediante 
-- el par (2,5).
-- ----------------------------------------------------------------------------

-- Lo siguiente significa que el tipo Complejo es lo mismo que decir (Double,Double)
type Complejo = (Double,Double)

-- ----------------------------------------------------------------------------
-- Ejercicio 14.1. Definir la función
--    sumaComplejos :: Complejo -> Complejo -> Complejo
-- tal que '(sumaComplejos x y)' es la suma de los números complejos 'x' e 'y'.
-- Por ejemplo,
--    sumaComplejos (2,3) (5,6)  ==  (7.0,9.0)
-- ----------------------------------------------------------------------------

sumaComplejos :: Complejo -> Complejo -> Complejo
sumaComplejos (x1,x2) (y1,y2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 14.2. Definir la función
--    productoComplejos :: Complejo -> Complejo -> Complejo
-- tal que '(productoComplejos x y)' es el producto de los números complejos
-- 'x' e 'y'. Por ejemplo,
--    productoComplejos (2,3) (5,6)  ==  (-8.0,27.0)
-- ----------------------------------------------------------------------------

productoComplejos :: Complejo -> Complejo -> Complejo
productoComplejos (x1,x2) (y1,y2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 14.3. Definir la función
--    cocienteComplejos :: Complejo -> Complejo -> Complejo
-- tal que '(cocienteComplejos x y)' es el cociente de los números complejos
-- 'x' e 'y'. Por ejemplo,
--    cocienteComplejos (3,2) (1,-2)  ==  (-0.2,1.6)
-- ----------------------------------------------------------------------------

cocienteComplejos :: Complejo -> Complejo -> Complejo
cocienteComplejos (x1,x2) (y1,y2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 14.4. Definir la función
--    conjugado :: Complejo -> Complejo
-- tal que '(conjugado x)' es el conjugado del número complejo 'x'. Por
-- ejemplo,
--    conjugado (2,3)  ==  (2.0,-3.0)
-- ----------------------------------------------------------------------------

conjugado :: Complejo -> Complejo
conjugado (x1,x2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 15. Los rectángulos pueden representarse por sus dimensiones, base
-- y altura, como un par de números enteros. Por ejemplo, (5,3) representa un
-- rectángulo de base 5 y altura 3.
--
-- Definir la función
--    mayorRectangulo :: (Int,Int) -> (Int,Int) -> (Int,Int)
-- tal que '(mayorRectangulo r1 r2)' es el rectángulo de mayor área entre 'r1'
-- y 'r2'. Por ejemplo,
--    mayorRectangulo (4,6) (3,7)  ==  (4,6)
--    mayorRectangulo (4,6) (3,8)  ==  (4,6)
--    mayorRectangulo (4,6) (3,9)  ==  (3,9)
-- ----------------------------------------------------------------------------

mayorRectangulo :: (Int,Int) -> (Int,Int) -> (Int,Int)
mayorRectangulo (x1,y1) (x2,y2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 16. Definir la función
--    cuadrante :: (Int,Int) -> Int
-- tal que '(cuadrante p)' es el cuadrante en el que se encuentra el punto 'p'.
-- Si el punto está sobre los ejes el resultado debe ser 0. Por ejemplo,
--    cuadrante (0,4)    ==  0
--    cuadrante (-3,0)   ==  0
--    cuadrante (0,0)    ==  0
--    cuadrante (3,5)    ==  1
--    cuadrante (-3,5)   ==  2
--    cuadrante (-3,-5)  ==  3
--    cuadrante (3,-5)   ==  4
-- ----------------------------------------------------------------------------

cuadrante :: (Int,Int) -> Int
cuadrante (x1,x2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 17. Definir la función
--    simetricoH :: (Int,Int) -> (Int,Int)
-- tal que '(simetricoH p)' es el punto simétrico de 'p' respecto del eje
-- horizontal. Por ejemplo,
--    simetricoH (2,5)   ==  (2,-5)
--    simetricoH (2,-5)  ==  (2,5)
-- ----------------------------------------------------------------------------

simetricoH :: (Int,Int) -> (Int,Int)
simetricoH (x1,x2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 18. Definir la función
--    simetricoV :: (Int,Int) -> (Int,Int)
-- tal que '(simetricoV p)' es el punto simétrico de 'p' respecto del eje
-- vertical. Por ejemplo,
--    simetricoV (2,5)   ==  (-2,5)
--    simetricoV (2,-5)  ==  (-2,-5)
-- ----------------------------------------------------------------------------

simetricoV :: (Int,Int) -> (Int,Int)
simetricoV (x1,x2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 19. Definir la función
--    distancia :: (Float,Float) -> (Float,Float) -> Float
-- tal que '(distancia p1 p2)' es la distancia entre los puntos 'p1' y 'p2'.
-- Por ejemplo,
--    distancia (1,2) (4,6)  ==  5.0
-- ----------------------------------------------------------------------------

distancia :: (Float,Float) -> (Float,Float) -> Float
distancia (x1,x2) (y1,y2) = undefined

-- ----------------------------------------------------------------------------
-- Ejercicio 20. Comprobar con QuickCheck que se verifica la propiedad
-- triangular de la distancia; es decir, dados tres puntos p1, p2 y p3, la
-- distancia de p1 a p3 es menor o igual que la suma de las distancias de p1 a
-- p2 y de p2 a p3.
-- ----------------------------------------------------------------------------

-- La propiedad es
prop_triangular :: (Float,Float) -> (Float,Float) -> (Float,Float) -> Bool
prop_triangular p1 p2 p3 = undefined

-- La comprobación es
--    > quickCheck prop_triangular

-- ----------------------------------------------------------------------------
-- Ejercicio 21. Definir la función
--    puntoMedio :: (Float,Float) -> (Float,Float) -> (Float,Float)
-- tal que '(puntoMedio p1 p2)' es el punto medio entre los puntos 'p1' y 'p2'.
-- Por ejemplo,
--    puntoMedio (0,2) (0,6)   ==  (0.0,4.0)
--    puntoMedio (-1,2) (7,6)  ==  (3.0,4.0)
-- ----------------------------------------------------------------------------

puntoMedio :: (Float,Float) -> (Float,Float) -> (Float,Float)
puntoMedio (x1,x2) (y1,y2) = undefined


-- ---------------------------------------------------------------------
-- Repaso de operaciones lógicas                                      --
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Ejercicio 22.1. La disyunción excluyente xor de dos fórmulas se
-- verifica si una es verdadera y la otra es falsa. Su tabla de verdad
-- es
--    x     | y     | xor x y
--    ------+-------+---------
--    True  | True  | False 
--    True  | False | True
--    False | True  | True
--    False | False | False
--    
-- Definir la función 
--    xor1 :: Bool -> Bool -> Bool
-- tal que (xor1 x y) es la disyunción excluyente de x e y, calculada a
-- partir de la tabla de verdad. Usar 4 ecuaciones, una por cada línea
-- de la tabla. 
-- ---------------------------------------------------------------------

xor1 :: Bool -> Bool -> Bool
xor1 = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 22.2. Definir la función 
--    xor2 :: Bool -> Bool -> Bool
-- tal que (xor2 x y) es la disyunción excluyente de x e y, calculada a
-- partir de la tabla de verdad y patrones. Usar 2 ecuaciones, una por
-- cada valor del primer argumento. 
-- ---------------------------------------------------------------------

xor2 :: Bool -> Bool -> Bool
xor2 = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 22.3. Definir la función 
--    xor3 :: Bool -> Bool -> Bool
-- tal que (xor3 x y) es la disyunción excluyente de x e y, calculada 
-- a partir de la disyunción (||), conjunción (&&) y negación (not). 
-- Usar 1 ecuación. 
-- ---------------------------------------------------------------------

xor3 :: Bool -> Bool -> Bool
xor3 x y = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 22.4. Definir la función 
--    xor4 :: Bool -> Bool -> Bool
-- tal que (xor3 x y) es la disyunción excluyente de x e y, calculada
-- a partir de desigualdad (/=). Usar 1 ecuación.
-- ---------------------------------------------------------------------

xor4 :: Bool -> Bool -> Bool
xor4 x y = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 22.5. Comprobar con QuickCheck que las cuatro definiciones
-- de xor son equivalentes.
-- ---------------------------------------------------------------------

-- La propiedad es
prop_xor_equivalentes :: Bool -> Bool -> Bool
prop_xor_equivalentes x y = undefined

-- La comprobación es

-- ---------------------------------------------------------------------
-- Ejercicio 23.1 Definir la función 
--    or3 :: Bool -> Bool -> Bool -> Bool
-- tal que (or3 a b c) es la disyunción entre a, b y c; es decir,
-- ocurre a o b o c. Definir la función usando '||'. Por ejemplo,
--    or3 True True False  ==  True
--    or3 False False False ==  False
-- ---------------------------------------------------------------------

or3 :: Bool -> Bool -> Bool-> Bool 
or3 = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 23.2 Definir la función 
--    or3' :: Bool -> Bool -> Bool -> Bool
-- tal que (or3' a b c) es la disyunción entre a, b y c; es decir,
-- ocurre a o b o c. Definir la función usando 'or' para listas.
-- Por ejemplo,
--    or3' True True False  ==  True
--    or3' False False False ==  False
-- ---------------------------------------------------------------------

or3' :: Bool -> Bool -> Bool -> Bool
or3' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 24.1 Definir la función 
--    and3 :: Bool -> Bool -> Bool -> Bool
-- tal que (and3 a b c) es la conjunción entre a, b y c; es decir,
-- ocurre a y b y c. Definir la función usando '&&'. Por ejemplo,
--    and3 True True True  ==  True
--    and3 False True False ==  False
-- ---------------------------------------------------------------------

and3 :: Bool -> Bool -> Bool -> Bool
and3 = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 24.2 Definir la función 
--    and3' :: Bool -> Bool -> Bool -> Bool 
-- tal que (and3' a b c) es la conjunción entre a, b y c; es decir,
-- ocurre a o b o c. Definir la función usando 'and' para listas.
-- Por ejemplo,
--    and3' True True True  ==  True
--    and3' False True False ==  False
-- ---------------------------------------------------------------------

and3' :: Bool -> Bool -> Bool -> Bool
and3' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 25.1. Definir la función 
--    siglo20 :: Int -> Bool 
-- tal que (siglo20 x) indica si el ańo x perteneció al siglo 20; es decir,
-- si está comprendido entre el ańo 1901 y 2000.
-- Por ejemplo,
--    siglo20 1902  == True
--    siglo20 2001 == False
-- ---------------------------------------------------------------------

siglo20 :: Int -> Bool
siglo20 = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 25.2. Definir la función 
--    noSiglo20 :: Int -> Bool 
-- tal que (noSiglo20 x) indica si el ańo x no perteneció al siglo 20; es decir,
-- si no está comprendido entre el ańo 1901 y 2000.
-- Definirla de tres formas distintas, una usando la función (siglo20 x), otra
-- usando '&&' y otra usando '||'.
--
-- Por ejemplo,
--    noSiglo20 1902  == False
--    noSiglo20 2001 == True
-- ---------------------------------------------------------------------

noSiglo20 :: Int -> Bool
noSiglo20 = undefined
noSiglo20' = undefined 
noSiglo20'' = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 26. Definir la función 
--    xnor :: Bool -> Bool -> Bool 
-- tal que (xnor a b) se calcula con su tabla de verdad, que
-- es
--    x     | y     | xnor x y
--    ------+-------+---------
--    False | False | True 
--    False | True  | False
--    True  | False | False
--    True  | True  | True
--
-- Emplear solo operadores lógicos (&&, ||, not).
-- 
-- Por ejemplo,
--    xnor True True  ==  True
--    xnor False True ==  False
--    xnor False False  ==  True
-- ---------------------------------------------------------------------

xnor :: Bool -> Bool -> Bool
xnor = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 27. Definir la función 
--    aprueba :: Float -> Float -> Float -> Bool
-- tal que (aprueba n1 n2 n3) indica si con las notas de los
-- exámenes parciales n1, n2 y n3 se consigue aprobar la
-- asignatura. Los criterios para aprobar la asignatura son los siguientes:
--   * La media de las notas debe ser mayor o igual que 5, y
--   * Cada una de las notas de los exámenes parciales son mayor o igual
--     que 4.0,
--   * O en el último exámen se obtuvo un 10 (entonces siempre se aprueba)
-- Por ejemplo,
--    aprueba 5.0 6.0 5.0 == True
--    aprueba 1.5 6.0 8.0 == False
--    aprueba 3.7 1.5 10.0 == True
-- ---------------------------------------------------------------------

aprueba :: Float -> Float -> Float -> Bool
aprueba = undefined

-- ---------------------------------------------------------------------
-- Ejercicio 28. Comprobar las leyes de Morgan con QuickCheck. Las
-- leyes de Morgan se definen como sigue:
--   * ley 1: no (A o B) == (no A) y (no B)
--   * ley 2: no (A y B) == (no A) o (no B)
-- Consejo: definir cada ley como una función por separado para componer
-- la propiedad
-- ---------------------------------------------------------------------

ley1:: Bool -> Bool -> Bool 
ley1 = undefined

ley2:: Bool -> Bool -> Bool 
ley2 = undefined

-- La propiedad es
prop_leyes_morgan :: Bool -> Bool -> Bool 
prop_leyes_morgan = undefined