{"id":7848,"date":"2022-11-26T08:43:48","date_gmt":"2022-11-26T07:43:48","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=7848"},"modified":"2022-11-26T08:44:10","modified_gmt":"2022-11-26T07:44:10","slug":"26-nov-22","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/26-nov-22\/","title":{"rendered":"PFH: La semana en Exercitium (26 de noviembre de 2022)"},"content":{"rendered":"<p>Esta semana he publicado en <a href=\"http:\/\/bit.ly\/2sqPtGs\">Exercitium<\/a> las soluciones de los siguientes problemas:<\/p>\n<ul>\n<li><a href=\"#ej1\">1. Aplica seg\u00fan propiedad<\/a><\/li>\n<li><a href=\"#ej2\">2. M\u00e1ximo de una lista<\/a><\/li>\n<li><a href=\"#ej3\">3. Movimientos en el plano<\/a><\/li>\n<li><a href=\"#ej4\">4. El tipo de figuras geom\u00e9tricas<\/a><\/li>\n<li><a href=\"#ej5\">5. El tipo de los n\u00fameros naturales<\/a><\/li>\n<\/ul>\n<p>A continuaci\u00f3n se muestran las soluciones.<br \/>\n<!--more--><br \/>\n<a name=\"ej1\"><\/a><\/p>\n<h3>1. Aplica seg\u00fan propiedad<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   filtraAplica :: (a -> b) -> (a -> Bool) -> [a] -> [b]\n<\/pre>\n<p>tal que <code>filtraAplica f p xs<\/code> es la lista obtenida aplic\u00e1ndole a los elementos de <code>xs<\/code> que cumplen el predicado <code>p<\/code> la funci\u00f3n <code>f<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   filtraAplica (4+) (<3) [1..7]  ==  [5,6]\n<\/pre>\n<p><b>1.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Test.QuickCheck.HigherOrder (quickCheck')\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nfiltraAplica1 :: (a -> b) -> (a -> Bool) -> [a] -> [b]\nfiltraAplica1 f p xs = [f x | x <- xs, p x]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nfiltraAplica2 :: (a -> b) -> (a -> Bool) -> [a] -> [b]\nfiltraAplica2 f p xs = map f (filter p xs)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nfiltraAplica3 :: (a -> b) -> (a -> Bool) -> [a] -> [b]\nfiltraAplica3 _ _ [] = []\nfiltraAplica3 f p (x:xs) | p x       = f x : filtraAplica3 f p xs\n                         | otherwise = filtraAplica3 f p xs\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nfiltraAplica4 :: (a -> b) -> (a -> Bool) -> [a] -> [b]\nfiltraAplica4 f p = foldr g []\n  where g x y | p x       = f x : y\n              | otherwise = y\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\nfiltraAplica5 :: (a -> b) -> (a -> Bool) -> [a] -> [b]\nfiltraAplica5 f p =\n  foldr (\\x y -> if p x then f x : y else y) []\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_filtraAplica :: (Int -> Int) -> (Int -> Bool) -> [Int] -> Bool\nprop_filtraAplica f p xs =\n  all (== filtraAplica1 f p xs)\n      [filtraAplica2 f p xs,\n       filtraAplica3 f p xs,\n       filtraAplica4 f p xs,\n       filtraAplica5 f p xs]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck' prop_filtraAplica\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> sum (filtraAplica1 id even [1..5*10^6])\n--    6250002500000\n--    (2.92 secs, 1,644,678,696 bytes)\n--    \u03bb> sum (filtraAplica2 id even [1..5*10^6])\n--    6250002500000\n--    (1.17 secs, 1,463,662,848 bytes)\n--    \u03bb> sum (filtraAplica3 id even [1..5*10^6])\n--    6250002500000\n--    (3.18 secs, 1,964,678,640 bytes)\n--    \u03bb> sum (filtraAplica4 id even [1..5*10^6])\n--    6250002500000\n--    (2.64 secs, 1,924,678,752 bytes)\n--    \u03bb> sum (filtraAplica5 id even [1..5*10^6])\n--    6250002500000\n--    (2.61 secs, 1,824,678,712 bytes)\n<\/pre>\n<p><b>1.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom functools import reduce\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\nfrom typing import Callable, TypeVar\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\nA = TypeVar('A')\nB = TypeVar('B')\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef filtraAplica1(f: Callable[[A], B],\n                  p: Callable[[A], bool],\n                  xs: list[A]) -> list[B]:\n    return [f(x) for x in xs if p(x)]\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef filtraAplica2(f: Callable[[A], B],\n                  p: Callable[[A], bool],\n                  xs: list[A]) -> list[B]:\n    return list(map(f, filter(p, xs)))\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef filtraAplica3(f: Callable[[A], B],\n                  p: Callable[[A], bool],\n                  xs: list[A]) -> list[B]:\n    if not xs:\n        return []\n    if p(xs[0]):\n        return [f(xs[0])] + filtraAplica3(f, p, xs[1:])\n    return filtraAplica3(f, p, xs[1:])\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\ndef filtraAplica4(f: Callable[[A], B],\n                  p: Callable[[A], bool],\n                  xs: list[A]) -> list[B]:\n    def g(ys: list[B], x: A) -> list[B]:\n        if p(x):\n            return ys + [f(x)]\n        return ys\n\n    return reduce(g, xs, [])\n\n# 5\u00aa soluci\u00f3n\n# ===========\n\ndef filtraAplica5(f: Callable[[A], B],\n                  p: Callable[[A], bool],\n                  xs: list[A]) -> list[B]:\n    r = []\n    for x in xs:\n        if p(x):\n            r.append(f(x))\n    return r\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.lists(st.integers()))\ndef test_filtraAplica(xs: list[int]) -> None:\n    f = lambda x: x + 4\n    p = lambda x: x < 3\n    r = filtraAplica1(f, p, xs)\n    assert filtraAplica2(f, p, xs) == r\n    assert filtraAplica3(f, p, xs) == r\n    assert filtraAplica4(f, p, xs) == r\n    assert filtraAplica5(f, p, xs) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q aplica_segun_propiedad.py\n#    1 passed in 0.25s\n\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('filtraAplica1(lambda x: x, lambda x: x % 2 == 0, range(10**5))')\n#    0.02 segundos\n#    >>> tiempo('filtraAplica2(lambda x: x, lambda x: x % 2 == 0, range(10**5))')\n#    0.01 segundos\n#    >>> tiempo('filtraAplica3(lambda x: x, lambda x: x % 2 == 0, range(10**5))')\n#    Process Python violaci\u00f3n de segmento (core dumped)\n#    >>> tiempo('filtraAplica4(lambda x: x, lambda x: x % 2 == 0, range(10**5))')\n#    4.07 segundos\n#    >>> tiempo('filtraAplica5(lambda x: x, lambda x: x % 2 == 0, range(10**5))')\n#    0.01 segundos\n#\n#    >>> tiempo('filtraAplica1(lambda x: x, lambda x: x % 2 == 0, range(10**7))')\n#    1.66 segundos\n#    >>> tiempo('filtraAplica2(lambda x: x, lambda x: x % 2 == 0, range(10**7))')\n#    1.00 segundos\n#    >>> tiempo('filtraAplica5(lambda x: x, lambda x: x % 2 == 0, range(10**7))')\n#    1.21 segundos\n<\/pre>\n<p><a name=\"ej2\"><\/a><\/p>\n<h3>2. M\u00e1ximo de una lista<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   maximo :: Ord a => [a] -> a\n<\/pre>\n<p>tal que <code>maximo xs<\/code> es el m\u00e1ximo de la lista <code>xs<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   maximo [3,7,2,5]                  ==  7\n   maximo [\"todo\",\"es\",\"falso<\/b>      ==  \"todo\"\n   maximo [\"menos\",\"alguna\",\"cosa<\/b>  ==  \"menos\"\n<\/pre>\n<p><b>2.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Data.List (foldl1')\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nmaximo1 :: Ord a => [a] -> a\nmaximo1 [x]      = x\nmaximo1 (x:y:ys) = max x (maximo1 (y:ys))\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nmaximo2 :: Ord a => [a] -> a\nmaximo2 = foldr1 max\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nmaximo3 :: Ord a => [a] -> a\nmaximo3 = foldl1' max\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nmaximo4 :: Ord a => [a] -> a\nmaximo4 = maximum\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_maximo :: NonEmptyList Int -> Bool\nprop_maximo (NonEmpty xs) =\n  all (== maximo1 xs)\n      [maximo2 xs,\n       maximo3 xs]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_maximo\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> maximo1 [0..5*10^6]\n--    5000000\n--    (3.42 secs, 1,783,406,728 bytes)\n--    \u03bb> maximo2 [0..5*10^6]\n--    5000000\n--    (0.80 secs, 934,638,080 bytes)\n--    \u03bb> maximo3 [0..5*10^6]\n--    5000000\n--    (0.12 secs, 360,591,360 bytes)\n--    \u03bb> maximo4 [0..5*10^6]\n--    5000000\n--    (1.40 secs, 892,891,608 bytes)\n<\/pre>\n<p><b>2.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom abc import abstractmethod\nfrom functools import reduce\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\nfrom typing import Any, TypeVar, Protocol\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\nA = TypeVar('A', bound=\"Comparable\")\n\nclass Comparable(Protocol):\n    \"\"\"Para comparar\"\"\"\n    @abstractmethod\n    def __eq__(self, other: Any) -> bool:\n        pass\n\n    @abstractmethod\n    def __lt__(self: A, other: A) -> bool:\n        pass\n\n    def __gt__(self: A, other: A) -> bool:\n        return (not self < other) and self != other\n\n    def __le__(self: A, other: A) -> bool:\n        return self < other or self == other\n\n    def __ge__(self: A, other: A) -> bool:\n        return not self < other\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef maximo1(xs: list[A]) -> A:\n    if len(xs) == 1:\n        return xs[0]\n    return max(xs[0], maximo1(xs[1:]))\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef maximo2(xs: list[A]) -> A:\n    return reduce(max, xs)\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef maximo3(xs: list[A]) -> A:\n    return max(xs)\n\n# ============================\n\n# La propiedad es\n@given(st.lists(st.integers(), min_size=2))\ndef test_maximo(xs: list[int]) -> None:\n    r = maximo1(xs)\n    assert maximo2(xs) == r\n    assert maximo3(xs) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q maximo_de_una_lista.py\n#    1 passed in 0.33s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('maximo1(range(2*10**4))')\n#    0.03 segundos\n#    >>> tiempo('maximo2(range(2*10**4))')\n#    0.00 segundos\n#    >>> tiempo('maximo3(range(2*10**4))')\n#    0.00 segundos\n#\n#    >>> tiempo('maximo2(range(5*10**6))')\n#    0.38 segundos\n#    >>> tiempo('maximo3(range(5*10**6))')\n#    0.21 segundos\n<\/pre>\n<p><a name=\"ej3\"><\/a><\/p>\n<h3>3. Movimientos en el plano<\/h3>\n<p>Se consideran el tipo de las posiciones del plano definido por<\/p>\n<pre lang=\"text\">\n   type Posicion = (Int,Int)\n   <7p\ny el tipo de las direcciones definido por\n<pre lang=\"text\">\n   data Direccion = Izquierda | Derecha | Arriba | Abajo\n     deriving Show\n<\/pre>\n<p>Definir las siguientes funciones<\/p>\n<pre lang=\"text\">\n   opuesta     :: Direccion -> Direccion\n   movimiento  :: Posicion -> Direccion -> Posicion\n   movimientos :: Posicion -> [Direccion] -> Posicion\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li><code>opuesta d<\/code> es la direcci\u00f3n opuesta de <code>d<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     opuesta Izquierda == Derecha\n<\/pre>\n<ul>\n<li><code>movimiento p d<\/code> es la posici\u00f3n reultante de moverse, desde la  posici\u00f3n <code>p<\/code>, un paso en la direcci\u00f3n <code>d<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     movimiento (2,5) Arriba          == (2,6)\n     movimiento (2,5) (opuesta Abajo) == (2,6)\n<\/pre>\n<ul>\n<li><code>movimientos p ds<\/code> es la posici\u00f3n obtenida aplicando la lista de movimientos seg\u00fan las direcciones de <code>ds<\/code> a la posici\u00f3n <code>p<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     movimientos (2,5)  [Arriba, Izquierda] == (1,6)\n<\/pre>\n<p><b>3.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\ntype Posicion = (Int,Int)\n\ndata Direccion = Izquierda | Derecha | Arriba | Abajo\n  deriving Show\n\n-- Definici\u00f3n de opuesta\n-- =====================\n\nopuesta :: Direccion -> Direccion\nopuesta Izquierda = Derecha\nopuesta Derecha   = Izquierda\nopuesta Arriba    = Abajo\nopuesta Abajo     = Arriba\n\n-- 1\u00aa definici\u00f3n de movimiento\n-- ===========================\n\nmovimiento1 :: Posicion -> Direccion -> Posicion\nmovimiento1 (x,y) Izquierda = (x-1,y)\nmovimiento1 (x,y) Derecha   = (x+1,y)\nmovimiento1 (x,y) Arriba    = (x,y+1)\nmovimiento1 (x,y) Abajo     = (x,y-1)\n\n-- 2\u00aa definici\u00f3n de movimiento\n-- ===========================\n\nmovimiento2 :: Posicion -> Direccion -> Posicion\nmovimiento2 (x,y) d =\n  case d of\n    Izquierda -> (x-1,y)\n    Derecha   -> (x+1,y)\n    Arriba    -> (x,y+1)\n    Abajo     -> (x,y-1)\n\n-- 1\u00aa definici\u00f3n de movimientos\n-- ============================\n\nmovimientos1 :: Posicion -> [Direccion] -> Posicion\nmovimientos1 p []     = p\nmovimientos1 p (d:ds) = movimientos1 (movimiento1 p d) ds\n\n-- 2\u00aa definici\u00f3n de movimientos\n-- ============================\n\nmovimientos2 :: Posicion -> [Direccion] -> Posicion\nmovimientos2 = foldl movimiento1\n<\/pre>\n<p><b>3.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom enum import Enum\nfrom functools import reduce\n\nPosicion = tuple[int, int]\n\nDireccion = Enum('Direccion', ['Izquierda', 'Derecha', 'Arriba', 'Abajo'])\n\n# 1\u00aa definici\u00f3n de opuesta\n# ========================\n\ndef opuesta1(d: Direccion) -> Direccion:\n    if d == Direccion.Izquierda:\n        return Direccion.Derecha\n    if d == Direccion.Derecha:\n        return Direccion.Izquierda\n    if d == Direccion.Arriba:\n        return Direccion.Abajo\n    if d == Direccion.Abajo:\n        return Direccion.Arriba\n    assert False\n\n# 2\u00aa definici\u00f3n de opuesta\n# ========================\n\ndef opuesta2(d: Direccion) -> Direccion:\n    match d:\n        case Direccion.Izquierda:\n            return Direccion.Derecha\n        case Direccion.Derecha:\n            return Direccion.Izquierda\n        case Direccion.Arriba:\n            return Direccion.Abajo\n        case Direccion.Abajo:\n            return Direccion.Arriba\n    assert False\n\n# 1\u00aa definici\u00f3n de movimiento\n# ===========================\n\ndef movimiento1(p: Posicion, d: Direccion) -> Posicion:\n    (x, y) = p\n    if d == Direccion.Izquierda:\n        return (x - 1, y)\n    if d == Direccion.Derecha:\n        return (x + 1, y)\n    if d == Direccion.Arriba:\n        return (x, y + 1)\n    if d == Direccion.Abajo:\n        return (x, y - 1)\n    assert False\n\n# 2\u00aa definici\u00f3n de movimiento\n# ===========================\n\ndef movimiento2(p: Posicion, d: Direccion) -> Posicion:\n    (x, y) = p\n    match d:\n        case Direccion.Izquierda:\n            return (x - 1, y)\n        case Direccion.Derecha:\n            return (x + 1, y)\n        case Direccion.Arriba:\n            return (x, y + 1)\n        case Direccion.Abajo:\n            return (x, y - 1)\n    assert False\n\n# 1\u00aa definici\u00f3n de movimientos\n# ============================\n\ndef movimientos1(p: Posicion, ds: list[Direccion]) -> Posicion:\n    if not ds:\n        return p\n    return movimientos1(movimiento1(p, ds[0]), ds[1:])\n\n# 2\u00aa definici\u00f3n de movimientos\n# ============================\n\ndef movimientos2(p: Posicion, ds: list[Direccion]) -> Posicion:\n    return reduce(movimiento1, ds, p)\n<\/pre>\n<p><a name=\"ej4\"><\/a><\/p>\n<h3>4. El tipo de figuras geom\u00e9tricas<\/h3>\n<p>Se consideran las figuras geom\u00e9tricas formadas por circulos (definidos por su radio) y rect\u00e1ngulos (definidos por su base y su altura). El tipo de las figura geom\u00e9tricas se define por<\/p>\n<pre lang=\"text\">\n   data Figura = Circulo Float | Rect Float Float\n<\/pre>\n<p>Definir las funciones<\/p>\n<pre lang=\"text\">\n   area     :: Figura -> Float\n   cuadrado :: Float -> Figura\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li><code>area f<\/code> es el \u00e1rea de la figura <code>f<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     area (Circulo 1)   ==  3.1415927\n     area (Circulo 2)   ==  12.566371\n     area (Rect 2 5)    ==  10.0\n <\/pre>\n<ul>\n<li><code>cuadrado n<\/code> es el cuadrado de lado <code>n<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     area (cuadrado 3)  ==  9.0\n<\/pre>\n<p><b>4.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\ndata Figura = Circulo Float | Rect Float Float\n\narea :: Figura -> Float\narea (Circulo r) = pi*r^2\narea (Rect x y)  = x*y\n\ncuadrado :: Float -> Figura\ncuadrado n = Rect n n\n<\/pre>\n<p><b>4.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom dataclasses import dataclass\nfrom math import pi\n\n@dataclass\nclass Figura:\n    \"\"\"Figuras geom\u00e9tricas\"\"\"\n\n@dataclass\nclass Circulo(Figura):\n    r: float\n\n@dataclass\nclass Rect(Figura):\n    x: float\n    y: float\n\ndef area(f: Figura) -> float:\n    match f:\n        case Circulo(r):\n            return pi * r**2\n        case Rect(x, y):\n            return x * y\n    assert False\n\ndef cuadrado(n: float) -> Figura:\n    return Rect(n, n)\n<\/pre>\n<p><a name=\"ej5\"><\/a><\/p>\n<h3>5. El tipo de los n\u00fameros naturales<\/h3>\n<p>El tipo de los n\u00fameros raturales se puede definir por<\/p>\n<pre lang=\"text\">\n   data Nat = Cero | Suc Nat\n     deriving (Show, Eq)\n<\/pre>\n<p>de forma que <code>Suc (Suc (Suc Cero))<\/code> representa el n\u00famero 3.<\/p>\n<p>Definir las siguientes funciones<\/p>\n<pre lang=\"text\">\n   nat2int :: Nat -> Int\n   int2nat :: Int -> Nat\n   suma    :: Nat -> Nat -> Nat\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li><code>nat2int n<\/code> es el n\u00famero entero correspondiente al n\u00famero natural <code>n<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     nat2int (Suc (Suc (Suc Cero)))  ==  3\n<\/pre>\n<ul>\n<li><code>int2nat n<\/code> es el n\u00famero natural correspondiente al n\u00famero entero <code>n<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     int2nat 3  ==  Suc (Suc (Suc Cero))\n<\/pre>\n<ul>\n<li><code>suma m n<\/code> es la suma de los n\u00famero naturales <code>m<\/code> y <code>n<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     \u03bb> suma (Suc (Suc Cero)) (Suc Cero)\n     Suc (Suc (Suc Cero))\n     \u03bb> nat2int (suma (Suc (Suc Cero)) (Suc Cero))\n     3\n     \u03bb> nat2int (suma (int2nat 2) (int2nat 1))\n     3\n<\/pre>\n<p><b>5.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\ndata Nat = Cero | Suc Nat\n  deriving (Show, Eq)\n\nnat2int :: Nat -> Int\nnat2int Cero    = 0\nnat2int (Suc n) = 1 + nat2int n\n\nint2nat :: Int -> Nat\nint2nat 0 = Cero\nint2nat n = Suc (int2nat (n-1))\n\nsuma :: Nat -> Nat -> Nat\nsuma Cero    n = n\nsuma (Suc m) n = Suc (suma m n)\n<\/pre>\n<p><b>5.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom dataclasses import dataclass\n\n@dataclass\nclass Nat:\n    pass\n\n@dataclass\nclass Cero(Nat):\n    pass\n\n@dataclass\nclass Suc(Nat):\n    n: Nat\n\ndef nat2int(n: Nat) -> int:\n    match n:\n        case Cero():\n            return 0\n        case Suc(n):\n            return 1 + nat2int(n)\n    assert False\n\ndef int2nat(n: int) -> Nat:\n    if n == 0:\n        return Cero()\n    return Suc(int2nat(n - 1))\n\ndef suma(m: Nat, n: Nat) -> Nat:\n    match m:\n        case Cero():\n            return n\n        case Suc(m):\n            return Suc(suma(m, n))\n    assert False\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Esta semana he publicado en Exercitium las soluciones de los siguientes problemas: 1. Aplica seg\u00fan propiedad 2. M\u00e1ximo de una lista 3. Movimientos en el plano 4. El tipo de figuras geom\u00e9tricas 5. El tipo de los n\u00fameros naturales A continuaci\u00f3n se muestran las soluciones.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[337],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7848"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=7848"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7848\/revisions"}],"predecessor-version":[{"id":7849,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7848\/revisions\/7849"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=7848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=7848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=7848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}