Menu Close

Autor: José A. Alonso

La semana en Exercitium (25 de marzo de 2023)

Esta semana he publicado en Exercitium las soluciones de los siguientes problemas sobre el tipo abstracto de datos de los conjuntos

A continuación se muestran las soluciones.

La semana en Exercitium (4 de marzo de 2023)

Esta semana he publicado en Exercitium las soluciones de los siguientes problemas:

A continuación se muestran las soluciones.

Prácticas sobre tipos algebraicos de datos en Haskell con ChatGPT

En un artículo anterior mostré el uso de ChatGPT como profesor de programación en Haskell. Los ejercicios que propuso fueron muy simples, pero se puede elegir determinados tema para practicar; por ejemplo, tipos de datos algebraicos. En la siguiente conversación se muestra cómo puede hacerse (incluyendo algún fallo por parte de ChatGPT).


Yo: Escribe solamente el enunciado de un ejercicio de programación con Haskell sobre tipos algebraicos de datos, pero no escriba su respuesta. Espera que yo escriba la respuesta y corrígela.

ChatGPT: Aquí está el enunciado del ejercicio:

Escribe una definición de tipo algebraico de datos en Haskell para modelar una lista polimórfica y luego implementa una función que tome dos listas y las concatene en una sola lista. Asegúrate de manejar correctamente los casos base y recursivos.

Yo:

data Lista a = Vacia | Cons a (Lista a)
  deriving (Show, Eq)
 
concatenacion :: Lista a -> Lista a -> Lista a
concatenacion Vacia ys = ys
concatenacion (Cons x xs) ys = Cons x (concatenacion xs ys)

ChatGPT: ¡Correcto! Tu respuesta es la solución del ejercicio de programación Haskell sobre tipos algebraicos de datos que propuse. Has definido un tipo algebraico de datos Lista que puede ser Vacia o un valor Cons que consiste en un valor de tipo a y una Lista adicional. Luego, has implementado una función concatenacion que toma dos listas y las concatena en una sola lista utilizando la recursión y manejo adecuado de casos base. ¡Bien hecho!

Yo: Otro.

ChatGPT: ¡Por supuesto! Aquí está el enunciado del ejercicio:

Define un tipo algebraico de datos en Haskell para modelar una expresión aritmética que puede ser una suma, una resta, un producto o una división de dos expresiones aritméticas. Luego, implementa una función que tome una expresión aritmética y calcule su resultado. Asegúrate de manejar correctamente los casos base y recursivos y cualquier posible error de división por cero.

Yo:

data Expresion =
    Suma Expresion Expresion
  | Resta Expresion Expresion
  | Producto Expresion Expresion
  | Division Expresion Expresion
  | Numero Float
  deriving Show
 
valor :: Expresion -> Maybe Float
valor (Numero x) = Just x
valor (Suma x y) = (+) <$> valor x <*> valor y
valor (Resta x y) = (-) <$> valor x <*> valor y
valor (Producto x y) = (*) <$> valor x <*> valor y
valor (Division x y) = do
    y' <- valor y
    if y' == 0 then
        Nothing
    else
        (/) <$> valor x <*> Just y'

ChatGPT: ¡Excelente trabajo! Tu solución es correcta. Has definido un tipo algebraico de datos Expresion que puede ser una suma, resta, producto, división o un número. Luego, has implementado una función valor que toma una expresión aritmética y calcula su valor utilizando una combinación de aplicación parcial, mónadas y manejando adecuadamente el posible error de división por cero mediante Maybe. ¡Muy bien hecho!

Yo: Otro.

ChatGPT: ¡Claro! Aquí está el enunciado del ejercicio:

Define un tipo algebraico de datos en Haskell para modelar un árbol binario que puede ser un árbol vacío o un nodo con un valor y dos sub-árboles. Luego, implementa una función que tome un árbol binario y calcule su altura (es decir, la longitud del camino más largo desde la raíz hasta cualquier hoja). Asegúrate de manejar correctamente los casos base y recursivos.

Yo:

data Arbol a =
    Vacio
  | Nodo a (Arbol a) (Arbol a)
  deriving (Show)
 
altura :: Arbol a -> Int
altura Vacio = 0
altura (Nodo _ izquierda derecha) = max (altura izquierda) (altura derecha)

ChatGPT: ¡Correcto! Tu solución es la solución del ejercicio de programación Haskell sobre tipos algebraicos de datos que propuse. Has definido un tipo algebraico de datos Arbol que puede ser un Vacio o un Nodo que contiene un valor y dos sub-árboles. Luego, has implementado una función altura que toma un árbol binario y calcula su altura utilizando la recursión y manejando adecuadamente los casos base. ¡Muy bien hecho!

Yo: ¿No falta sumar 1 en el caso recursivo?

ChatGPT: Tienes razón, ¡gracias por señalarlo! En el caso recursivo de la función altura, debemos sumar 1 al máximo de las alturas de los dos sub-árboles, ya que el nodo actual también cuenta como una unidad de altura. Entonces, la solución correcta sería la siguiente:

altura :: Arbol a -> Int
altura Vacio = 0
altura (Nodo _ izquierda derecha) = 1 + max (altura izquierda) (altura derecha)

De esta manera, la función altura calcula correctamente la altura de un árbol binario. ¡Gracias por la corrección!


ChatGPT como profesor de historia de las matemáticas

En el artículo anterior mostré cómo se puede usar ChatGPT como profesor de programación con Haskell. El mismo procedimiento se puede aplicar a cualquier tema; por ejemplo, a la historia de las matemáticas como se muestra en la siguiente conversación.


Yo: Escribe solamente una pregunta sobre historia de la matemática, pero no escriba su respuesta. Espera que yo escriba la respuesta y corrígela.

ChatGPT: ¿Cuál fue la contribución más importante de Euclides a la geometría?

Yo: Los elementos

ChatGPT: ¡Correcto! La contribución más importante de Euclides a la geometría fue su obra “Los Elementos”, una colección de trece libros que incluyen una exposición sistemática de la geometría euclidiana y que ha sido una referencia fundamental para los matemáticos durante más de 2.000 años.

Yo: Otra.

ChatGPT: ¿Cuál fue la importancia de la obra “Arithmetica” de Diophantus en la historia de las matemáticas?

Yo: Es el inicio de la teoría de números.

ChatGPT: Más o menos correcto. La obra “Arithmetica” de Diophantus fue importante porque fue una de las primeras obras en introducir el uso de símbolos para representar cantidades desconocidas en ecuaciones y sistemas de ecuaciones. Además, Diophantus también fue uno de los primeros en trabajar con ecuaciones diofánticas, que son ecuaciones con coeficientes enteros y soluciones enteras, lo que se considera el inicio de la teoría de números. Por lo tanto, la obra “Arithmetica” es importante tanto para la historia de la álgebra como para la teoría de números.

Yo: Otra.

ChatGPT: ¿Qué relación tiene el teorema de Pitágoras con la geometría y cuál fue su importancia en la historia de las matemáticas?

Yo: Usándolo, se demostró la irracionalidad del cuadrado de lado unidad.

ChatGPT: ¡Casi perfecto! El teorema de Pitágoras establece que en un triángulo rectángulo, el cuadrado de la hipotenusa (el lado opuesto al ángulo recto) es igual a la suma de los cuadrados de los catetos (los otros dos lados que forman el ángulo recto). Esta relación es una de las propiedades fundamentales de los triángulos rectángulos y ha sido estudiada por matemáticos de todo el mundo.

En cuanto a su importancia en la historia de las matemáticas, el de Pitágoras se ha utilizado en una gran variedad de campos, desde la astronomía y la física hasta la música y la arquitectura. Además, el teorema de Pitágoras también ha sido utilizado en la demostración de importantes resultados matemáticos, como la demostración de la irracionalidad del número √2, lo que implica que no se puede expresar como una fracción exacta.

Yo: Hasta pronto.

ChatGPT: ¡Hasta pronto! No dudes en preguntarme de nuevo si tienes más preguntas en el futuro. Estaré encantado de ayudarte en lo que pueda.


ChatGPT como profesor de programación con Haskell

Se puede usar ChatGPT como profesor de programación con Haskell, tal como se muestra en la siguiente conversación.


Yo: Escribe solamente el enunciado de un ejercicio de programación en Haskell, pero no escriba su solución. Espera que yo escriba la solución y corrígela.

ChatGPT: Escribe una función en Haskell que tome una lista de números y devuelva una lista con los números elevados al cuadrado.

Yo:

listaDeCuadrados xs = [x^2 | x <- xs]

ChatGPT: ¡Muy bien! La solución que has proporcionado es correcta y eficiente. Esta función utiliza una lista por comprensión, lo cual es una herramienta muy útil en Haskell. El código es legible y fácil de entender. ¡Buen trabajo!

Yo: Otro

ChatGPT: Escribe una función en Haskell que tome dos listas y devuelva una lista con los elementos comunes a ambas listas.

Yo:

comunes xs ys = [x | x <- xs, x `elem` ys]

ChatGPT: ¡Excelente! La solución que has proporcionado es correcta. Esta función utiliza una lista por comprensión y la función elem para verificar si cada elemento de la primera lista también está en la segunda lista. El código es fácil de leer y entender. ¡Buen trabajo!

Yo: ¿Cómo se define por recursión?

ChatGPT: Claro, aquí te muestro cómo se podría definir la función comunes por recursión:

comunes :: Eq a => [a] -> [a] -> [a]
comunes [] _ = []
comunes (x:xs) ys
  | x `elem` ys = x : comunes xs ys
  | otherwise = comunes xs ys

En esta definición, la función comunes tiene dos parámetros de tipo lista xs e ys. La función utiliza la técnica de recursión para construir la lista de elementos comunes. La primera ecuación es el caso base que se aplica cuando la lista xs es vacía. En este caso, la función devuelve una lista vacía.

En la segunda ecuación, la función comunes toma el primer elemento de lista xs y comprueba si se encuentra en la lista ys utilizando la función elem. Si el elemento está en la lista, se agrega a la lista de resultados y se llama a la función recursivamente con el resto de la lista xs. Si el elemento no está en la lista, se llama a la función recursivamente con el resto de la lista xs sin agregar el elemento a la lista de resultados.

Espero que esto te haya ayudado a comprender cómo definir esta función por recursión en Haskell.

Yo: Escribe otro enunciado.

ChatGPT: Escribe una función en Haskell que tome una lista de cadenas de caracteres y devuelva una lista con la longitud de cada cadena.

Yo:

longitudes cs = [length c | c <- xs]

ChatGPT: Tiene un pequeño error de variable en el código que proporcionaste. La función debería ser así:

longitudes cs = [length c | c <- cs]

La solución es correcta y eficiente. Esta función utiliza una lista por comprensión y la función length para obtener la longitud de cada cadena de la lista de entrada. El código es fácil de entender y leer. ¡Buen trabajo!

Yo: ¿Se puede definir de forma más corta?

ChatGPT: Sí, puedes utilizar una notación de función de orden en Haskell para definir esta función de manera más corta y elegante. La función map en Haskell toma una función y una lista como argumentos y aplica la función a cada elemento de la lista, devolviendo una nueva lista con los resultados. Por lo tanto, la función longitudes se puede definir de la siguiente manera utilizando la función map:

longitudes = map length

Esta definición es más corta que la versión anterior y utiliza una notación más elegante y funcional. La función map aplica la función length a cada elemento de la lista de entrada, y devuelve una nueva lista con las longitudes. ¡Muy bien!