PFH: La semana en Exercitium (2 de septiembre de 2022)
Esta semana he publicado en Exercitium las soluciones de los siguientes problemas:
A continuación se muestran las soluciones.
1. Tres iguales
Definir la función
1 |
tresIguales :: Int -> Int -> Int -> Bool |
tal que (tresIguales x y z)
se verifica si los elementos x
, y
y z
son iguales. Por ejemplo,
1 2 |
tresIguales 4 4 4 == True tresIguales 4 3 4 == False |
Soluciones en Haskell
1 2 |
tresIguales :: Int -> Int -> Int -> Bool tresIguales x y z = x == y && y == z |
El código se encuentra en GitHub.
Soluciones en Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from hypothesis import given, strategies as st # 1ª definición def tresIguales1(x: int, y: int, z: int) -> bool: return x == y and y == z # 2ª definición def tresIguales2(x: int, y: int, z: int) -> bool: return x == y == z # La propiedad de equivalencia es @given(st.integers(), st.integers(), st.integers()) def test_equiv_tresIguales(x, y, z): assert tresIguales1(x, y, z) == tresIguales2(x, y, z) # La comprobación es # src> poetry run pytest -q tres_iguales.py # 1 passed in 0.16s |
El código se encuentra en GitHub.
Comentarios
- La conjunción de
x
ey
se calcula- en Haskell, con
x && y
y - en Python, con
x and y
.
- en Haskell, con
- En Python,
x == y == z
es equivalente ax == y and y == z
.
2. Tres diferentes
Definir la función
1 |
tresDiferentes :: Int -> Int -> Int -> Bool |
tal que (tresDiferentes x y z)
se verifica si los elementos x
, y
y z
son distintos. Por ejemplo,
1 2 |
tresDiferentes 3 5 2 == True tresDiferentes 3 5 3 == False |
Soluciones en Haskell
1 2 |
tresDiferentes :: Int -> Int -> Int -> Bool tresDiferentes x y z = x /= y && x /= z && y /= z |
El código se encuentra en GitHub.
Soluciones en Python
1 2 |
def tresDiferentes(x: int, y: int, z: int) -> bool: return x != y and x != z and y != z |
El código se encuentra en GitHub.
Comentarios
- Para decidir si
x
ey
son distintos, se escribex /= y
en Haskell yx != y
en Python.
3. División segura
Definir la función
1 |
divisionSegura :: Double -> Double -> Double |
tal que (divisionSegura x y)
es x/y
si y no es cero y 9999
en caso contrario. Por ejemplo,
1 2 |
divisionSegura 7 2 == 3.5 divisionSegura 7 0 == 9999.0 |
Soluciones en Haskell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import Test.QuickCheck -- 1ª definición divisionSegura1 :: Double -> Double -> Double divisionSegura1 x y = if y == 0 then 9999 else x/y -- 2ª definición divisionSegura2 :: Double -> Double -> Double divisionSegura2 _ 0 = 9999 divisionSegura2 x y = x/y -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_divisionSegura :: Double -> Double -> Bool prop_divisionSegura x y = divisionSegura1 x y == divisionSegura2 x y -- La comprobación es -- λ> quickCheck prop_divisionSegura -- +++ OK, passed 100 tests. |
El código se encuentra en GitHub.
Soluciones en Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
from hypothesis import given, strategies as st # 1ª definición def divisionSegura1(x: float, y: float) -> float: if y == 0: return 9999.0 return x/y # 2ª definición def divisionSegura2(x: float, y: float) -> float: match y: case 0: return 9999.0 case _: return x/y # La propiedad de equivalencia es @given(st.floats(allow_nan=False, allow_infinity=False), st.floats(allow_nan=False, allow_infinity=False)) def test_equiv_divisionSegura(x, y): assert divisionSegura1(x, y) == divisionSegura2(x, y) # La comprobación es # src> poetry run pytest -q division_segura.py # 1 passed in 0.37s |
El código se encuentra en GitHub.
Comentarios
- El condicional se escribe en Haskell como
1 |
if <condición> then <valor1> else <valor2> |
y en Python como
1 2 3 |
if <condición>: return <valor1> return <valor2> |
- Una alternativa al uso de los condicionales son los patrones que en Haskell se escribe en los argumentos de las ecuaciones y en Python con
match cases
.
4. Disyunción excluyente
La disyunción excluyente de dos fórmulas se verifica si una es verdadera y la otra es falsa. Su tabla de verdad es
1 2 3 4 5 6 |
x | y | xor x y ------+-------+--------- True | True | False True | False | True False | True | True False | False | False |
Definir la función
1 |
xor :: Bool -> Bool -> Bool |
tal que (xor x y)
es la disyunción excluyente de x
e y
. Por ejemplo,
1 2 3 4 |
xor True True == False xor True False == True xor False True == True xor False False == False |
Soluciones en Haskell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import Test.QuickCheck -- 1ª solución xor1 :: Bool -> Bool -> Bool xor1 True True = False xor1 True False = True xor1 False True = True xor1 False False = False -- 2ª solución xor2 :: Bool -> Bool -> Bool xor2 True y = not y xor2 False y = y -- 3ª solución: xor3 :: Bool -> Bool -> Bool xor3 x y = (x || y) && not (x && y) -- 4ª solución: xor4 :: Bool -> Bool -> Bool xor4 x y = (x && not y) || (y && not x) -- 5ª solución: xor5 :: Bool -> Bool -> Bool xor5 x y = x /= y -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_xor :: Bool -> Bool -> Bool prop_xor x y = all (== xor1 x y) [xor2 x y, xor3 x y, xor4 x y, xor5 x y] -- La comprobación es -- λ> quickCheck prop_xor -- +++ OK, passed 100 tests. |
El código se encuentra en GitHub.
Soluciones en Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
from hypothesis import given, strategies as st # 1ª solución def xor1(x, y): match x, y: case True, True: return False case True, False: return True case False, True: return True case False, False: return False # 2ª solución def xor2(x: bool, y: bool) -> bool: if x: return not y return y # 3ª solución def xor3(x: bool, y: bool) -> bool: return (x or y) and not(x and y) # 4ª solución def xor4(x: bool, y: bool) -> bool: return (x and not y) or (y and not x) # 5ª solución def xor5(x: bool, y: bool) -> bool: return x != y # La propiedad de equivalencia es @given(st.booleans(), st.booleans()) def test_equiv_xor(x, y): assert xor1(x, y) == xor2(x, y) == xor3(x, y) == xor4(x, y) == xor5(x, y) # La comprobación es # src> poetry run pytest -q disyuncion_excluyente.py # 1 passed in 0.11s |
El código se encuentra en GitHub.
Comentarios
- La negación de
x
se escribe igual en Haskell y Python;not x
-
La disyunción de
x
ey
se escribe- en Haskell, como
x || y
y - en Python, como
x or y
.
- en Haskell, como
5. Mayor rectángulo
Las dimensiones de los rectángulos puede representarse por pares; por ejemplo, (5,3) representa a un rectángulo de base 5 y altura 3.
Definir la función
1 |
mayorRectangulo :: (Num a, Ord a) => (a,a) -> (a,a) -> (a,a) |
tal que (mayorRectangulo r1 r2)
es el rectángulo de mayor área entre r1
y r2
. Por ejemplo,
1 2 3 |
mayorRectangulo (4,6) (3,7) == (4,6) mayorRectangulo (4,6) (3,8) == (4,6) mayorRectangulo (4,6) (3,9) == (3,9) |
Soluciones en Haskell
1 2 3 4 |
mayorRectangulo :: (Num a, Ord a) => (a,a) -> (a,a) -> (a,a) mayorRectangulo (a,b) (c,d) | a*b >= c*d = (a,b) | otherwise = (c,d) |
El código se encuentra en GitHub.
Soluciones en Python
1 2 3 4 5 6 7 |
def mayorRectangulo(r1: tuple[float, float], r2: tuple[float, float]) -> tuple[float, float]: (a, b) = r1 (c, d) = r2 if a*b >= c*d: return (a, b) return (c, d) |
El código se encuentra en GitHub.