introalg:taller09_3
Diferencias
Muestra las diferencias entre dos versiones de la página.
Próxima revisión | Revisión previa | ||
introalg:taller09_3 [2009/04/11 02:11] – creado laura | introalg:taller09_3 [2018/08/10 03:03] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
- | =====Introducción a la Programación Funcional===== | + | ======Introducción a la Programación Funcional====== |
Después de iniciarnos en la programación lógica en prolog, vamos a empezar con la [[http:// | Después de iniciarnos en la programación lógica en prolog, vamos a empezar con la [[http:// | ||
- | ====El intérprete de haskell==== | + | =====Iniciando |
Al igual que con prolog, vamos a estar usando un intérprete de haskell. Un intérprete de haskell es un programa que entiende haskell, por lo tanto, puede entender y ejecutar los programas que vamos a hacer en haskell. El intérprete que vamos a estar usando es [[http:// | Al igual que con prolog, vamos a estar usando un intérprete de haskell. Un intérprete de haskell es un programa que entiende haskell, por lo tanto, puede entender y ejecutar los programas que vamos a hacer en haskell. El intérprete que vamos a estar usando es [[http:// | ||
A Hugs se lo invoca desde la //línea de comandos// o cliqueando sobre el icono en nuestro entorno gráfico. | A Hugs se lo invoca desde la //línea de comandos// o cliqueando sobre el icono en nuestro entorno gráfico. | ||
- | Una vez que el intérprete está activo, la pantalla se presenta con un //prompt// a la espera de **expresiones** a ser evaluadas | + | Una vez que el intérprete está activo, la pantalla se presenta con un //prompt// a la espera de // |
+ | < | ||
[laura@azul Taller]$ hugs | [laura@azul Taller]$ hugs | ||
__ __ __ __ ____ | __ __ __ __ ____ | ||
Línea 22: | Línea 22: | ||
Type :? for help | Type :? for help | ||
Hugs.Base> | Hugs.Base> | ||
+ | </ | ||
- | De este modo Hugs se convierte en una calculadora, | + | A diferencia de prolog, el intérprete de haskell tiene muchas funciones ya definidas, las que se incluyen en el llamado [[http:// |
- | + | ||
- | A diferencia de prolog, el intérprete de haskell tiene muchas funciones ya definidas, las que se incluyen en el llamado [[http:// | + | |
+ | < | ||
Hugs.Base> | Hugs.Base> | ||
42 | 42 | ||
Línea 37: | Línea 37: | ||
Hugs.Base> | Hugs.Base> | ||
"daba le arroz al a zorra elabad" | "daba le arroz al a zorra elabad" | ||
+ | </ | ||
Podemos salir del intérprete Hugs con '' | Podemos salir del intérprete Hugs con '' | ||
+ | < | ||
Hugs.Base> | Hugs.Base> | ||
[Leaving Hugs] | [Leaving Hugs] | ||
[laura@azul Taller]$ | [laura@azul Taller]$ | ||
+ | </ | ||
- | Así volvemos al modo normal de la computadora. | + | =====Incorporando conocimiento===== |
- | ====Incorporando | + | Para poder dar nuevas definiciones y/o funciones, además de las que se encuentran en el [[http:// |
- | Para poder dar nuevas definiciones y/o funciones, además | + | Como ejemplo, vamos a ver todo el proceso |
+ | < | ||
+ | sgn :: Int → Int | ||
+ | -- dado un entero x, //sgn// retorna su signo, de la siguiente forma: | ||
+ | -- retornará 1 si x es positivo, -1 si es negativo y 0 en cualquier otro caso. | ||
+ | </ | ||
+ | Para crear un programa se puede hacer mediante un editor de texto cualquiera (kate, bloc de notas, emacs...) | ||
+ | < | ||
+ | Hugs.Base> | ||
+ | </code> | ||
+ | Se nos ocurre la siguiente solución para el problema de la función '' | ||
+ | < | ||
+ | sgn :: Int -> Int | ||
+ | sgn x | 0< | ||
+ | | x< | ||
+ | | x=0 = 0 | ||
+ | </code> | ||
+ | Escribimos esta función en el archivo, lo guardamos, y lo cargamos en la memoria del intérprete para que esté disponible para usarla. Para cargar el archivo, usamos la instrucción '': | ||
+ | < | ||
+ | Hugs.Base> | ||
+ | ERROR " | ||
+ | </code> | ||
+ | Pero el intérprete indica un error! Por qué? En la última línea del programa, vemos que usamos el mismo símbolo " | ||
- | Un programa funcional es un [[http://es.wikipedia.org/wiki/Archivo_inform%C3%A1tico|archivo]] con terminación **'' | + | Las traducciones de los símbolos son más o menos directas, de todas formas preparamos una tabla de [[http://cs.famaf.unc.edu.ar/introalg/PDF/ |
- | Como ejemplo, vamos a ver todo el proceso | + | Para solucionar |
+ | < | ||
+ | sgn :: Int -> Int | ||
+ | sgn x | 0< | ||
+ | | x< | ||
+ | | x==0 = 0 | ||
+ | </ | ||
+ | Luego de guardar el programa, hay que **volver a cargarlo** para que el intérprete pueda usar la función corregida, si no lo cargamos, el intérprete se queda en el estado anterior, en el que no tenía la función porque ésta tenía un error. | ||
+ | < | ||
+ | Hugs.Base> | ||
+ | Main> | ||
+ | </code> | ||
+ | Ahora sí, la función es correcta y por ello el intérprete nos muestra el prompt '' | ||
- | sgn :: Int → Int | + | Podemos probar la nueva función con //casos de test//, y vamos a fijarnos en qué casos nos dá errores y por qué: |
- | -- dado un entero x, //sgn// retorna su signo, de la siguiente forma: | + | < |
- | -- retornará | + | Main> sgn 1 |
+ | 1 | ||
+ | Main> sgn 0 | ||
+ | 0 | ||
+ | </ | ||
+ | Ningún problema: funciona para los casos del manual :). | ||
+ | < | ||
+ | Main> sgn 123123123123 | ||
- | Para crear un //script// basta con invocar | + | Program error: arithmetic overflow |
+ | |||
+ | Main> sgn 123123123 | ||
+ | 1 | ||
+ | </code> | ||
+ | El número es demasiado grande y el intérprete se queda sin capacidad | ||
+ | < | ||
+ | Main> sgn (-1 | ||
+ | ERROR - Syntax error in expression (unexpected end of input) | ||
+ | </ | ||
+ | Error de sintaxis: no cerramos | ||
+ | < | ||
+ | Main> sgn " | ||
+ | ERROR - Type error in application | ||
+ | *** Expression | ||
+ | *** Term : " | ||
+ | *** Type : String | ||
+ | *** Does not match : Int | ||
+ | </ | ||
+ | Error de tipos: la función está definida para trabajar con enteros | ||
+ | < | ||
+ | Main> sgn 1.1 | ||
+ | ERROR - Cannot infer instance | ||
+ | *** Instance | ||
+ | *** Expression : sgn 1.1 | ||
+ | </ | ||
+ | Error de tipos: la función está definida para trabajar con enteros (Int), no con el tipo decimal (Fractional). | ||
+ | < | ||
+ | Main> sgn -1 | ||
+ | ERROR - Cannot infer instance | ||
+ | *** Instance | ||
+ | *** Expression : sgn - 1 | ||
- | Hugs.Base> :e cap8.hs | + | Main> sgn (-1) |
+ | -1 | ||
+ | </ | ||
+ | Error de precedencia: la aplicación de funciones tiene precedencia sobre cualquier otra operación, y por lo tanto el intérprete aplica primero la función. Al hacerlo, se encuentra con un error de tipos: en lugar de un número, encuentra como argumento otra función (la función " | ||
- | Una posible solución para el problema de la función signo es la siguiente: | + | =====Cómo declaramos |
- | sgn :: Int -> Int | + | La declaración del conocimiento en haskell tiene algunos parecidos y algunas diferencias con la declaración del conocimiento en prolog. |
- | sgn x | 0< | + | |
- | | x< | + | |
- | | x=0 = 0 | + | |
+ | Vemos que haskell declara el conocimiento en forma de // | ||
+ | < | ||
+ | sgn :: Int -> Int | ||
+ | sgn x | 0< | ||
+ | | x< | ||
+ | | x==0 = 0 | ||
+ | </ | ||
+ | La primera línea es la //signatura de tipos//, de la que vamos a hablar en la siguiente sección. Las otras tres líneas son la definición de la función. Podemos ver que esta función está definida por análisis por casos, distinguiendo tres casos: cuando x es positivo ('' | ||
- | Luego de guardar el programa, hay cargarlo para que el intérprete Hugs pueda empezar | + | Por lo tanto, lo que hay a la izquierda del símbolo " |
+ | < | ||
+ | sgn(X,Y) :- (0<X , Y=1) ; (X<0 , Y=(-1)) ; (X=0, Y=0). | ||
+ | </ | ||
+ | y la consultaríamos de la siguiente manera: | ||
+ | < | ||
+ | ?- sgn(33, | ||
+ | Y = 1 . | ||
+ | </ | ||
+ | De esta forma, indicamos que la variable " | ||
- | Hugs.Base> :l cap8.hs | + | Al igual que en prolog, las variables que se usan en haskell tienen alcance únicamente dentro de la definición de la función, pero, a diferencia de prolog, las variables se escriben en minúscula, de la misma forma que el nombre de las funciones. |
- | ERROR " | + | |
- | Pero el intérprete indica un error! Por qué? Porque | + | Vemos que al definir '' |
- | Las traducciones | + | Vamos a ver que en haskell hay varias formas |
- | Para solucionar el error, volvemos a editar el script con '': | ||
- | sgn :: Int -> Int | + | ===== Tipos de datos===== |
- | sgn x | 0< | + | |
- | | x< | + | |
- | | x==0 | + | |
+ | Haskell es un lenguaje tipado, es decir, todo dato pertenece a una clase o tipo de datos. En general, la definición de una función va precedida de su //signatura de tipos//, donde declaramos los tipos que están involucrados en la función: | ||
+ | < | ||
+ | sgn :: Int -> Int -- esta línea es la signatura de tipos de la función sgn | ||
+ | sgn x | 0< | ||
+ | | x< | ||
+ | | x==0 = 0 | ||
+ | </ | ||
- | Luego de guardar | + | La signatura |
- | + | <code> | |
- | Hugs.Base> | + | sgn :: Int -> Int |
- | Main> | + | reverse |
- | + | map :: (a -> b) -> [a] -> [b] | |
- | Ahora sí, la función es correcta | + | </ |
- | + | Pequeño ejercicio sobre la aridad((Recuerden | |
- | Podemos probar la nueva función con //casos de test// para ganar confianza en su **corrección**. | + | |
- | + | ||
- | Main> sgn 1 | + | |
- | 1 | + | |
- | Main> | + | |
- | 0 | + | |
- | Main> sgn -1 | + | |
- | ERROR - Cannot infer instance | + | |
- | *** Instance | + | |
- | *** Expression | + | |
- | + | ||
- | Main> sgn (-1) | + | |
- | -1 | + | |
- | Main> sgn 123123123123 | + | |
- | + | ||
- | Program error: arithmetic overflow | + | |
- | + | ||
- | Main> sgn 123123123 | + | |
- | 1 | + | |
- | Main> sgn 1.1 | + | |
- | ERROR - Cannot infer instance | + | |
- | *** Instance | + | |
- | *** Expression : sgn 1.1 | + | |
- | + | ||
- | Main> sgn (-1 | + | |
- | ERROR - Syntax error in expression (unexpected end of input) | + | |
- | + | ||
- | Main> sgn " | + | |
- | ERROR - Type error in application | + | |
- | *** Expression | + | |
- | *** Term : " | + | |
- | *** Type : String | + | |
- | *** Does not match : Int | + | |
- | + | ||
- | Main> map sgn [-10..10] | + | |
- | | + | |
- | + | ||
- | + | ||
- | Notamos los distintos tipos de errores | + | |
- | * Precedencia ('' | + | |
- | * Tipos ('' | + | |
- | * Sintaxis ('' | + | |
- | + | ||
- | + | ||
- | ===== Inferencia | + | |
- | + | ||
- | Haskell | + | |
+ | Pero incluso si no hiciéramos la declaración de tipos mediante la signatura (lo cual sería muy mala práctica!), | ||
+ | < | ||
Main> :t sgn | Main> :t sgn | ||
sgn :: Int -> Int | sgn :: Int -> Int | ||
- | + | </ | |
- | Como expresiones en general | + | < |
Main> :t 1 + 2.1 | Main> :t 1 + 2.1 | ||
1 + 2.1 :: Fractional a => a | 1 + 2.1 :: Fractional a => a | ||
- | | + | </ |
+ | < | ||
Main> :t 1+ sqrt 64 | Main> :t 1+ sqrt 64 | ||
1 + sqrt 64 :: Floating a => a | 1 + sqrt 64 :: Floating a => a | ||
- | | + | </ |
+ | < | ||
Main> :t 1+ " | Main> :t 1+ " | ||
ERROR - Cannot infer instance | ERROR - Cannot infer instance | ||
*** Instance | *** Instance | ||
*** Expression : 1 + " | *** Expression : 1 + " | ||
- | | + | </ |
+ | < | ||
Main> :t " | Main> :t " | ||
" | " | ||
- | | + | </ |
+ | < | ||
Main> :t reverse | Main> :t reverse | ||
reverse :: [a] -> [a] | reverse :: [a] -> [a] | ||
- | | + | </ |
+ | < | ||
Main> :t map | Main> :t map | ||
map :: (a -> b) -> [a] -> [b] | map :: (a -> b) -> [a] -> [b] | ||
+ | </ | ||
+ | De esta forma, nos resulta imposible escribir cualquier expresión que esté mal tipada, es decir, usando tipos distintos a los que se declaran en la definición de la función. De hecho, corre el rumor de que, en una versión de desarrollo de un popular intérprete de haskell (GHC), si el intérprete encontraba un error de tipos, borraba todo el código fuente! :-} | ||
- | Esta maquinaria **impide** que escribamos cualquier expresión que esté mal tipada. | + | Los tipos de datos se declaran con la primera letra en mayúscula: Int, Float, Char, String, etc. En cambio, las variables se declaran en minúscula. |
- | Todas las funciones suelen ir encabezadas por su signatura, es decir, el nombre | + | Veamos algunos |
- | sgn :: Int -> Int | + | ====Letras y números==== |
- | reverse :: [a] -> [a] | + | |
- | map :: (a -> b) -> [a] -> [b] | + | |
+ | En haskell tenemos diferentes tipos de números. Los que más vamos a estar usando son los enteros, que se llaman '' | ||
- | ===== Tuplas ===== | + | También tenemos el tipo '' |
- | Haskell maneja n-uplas de manera directa. Las n-uplas nos permiten agrupar datos para manejarlos como una sola cosa, como veremos más adelante. | ||
- | Incorporamos a '' | + | ====Tuplas==== |
- | suma3upla :: (Int, | + | Las n-uplas son conjuntos con un número |
- | suma3upla (x,y,z) = x+y+z | + | |
- | + | ||
- | sumaYResta :: Int -> Int -> (Int,Int) | + | |
- | sumaYResta x y = (x+y, x-y) | + | |
- | Y las probamos desde el //prompt//. | + | Veamos algunos ejemplos: |
+ | < | ||
+ | suma3upla :: (Int, | ||
+ | suma3upla (x,y,z) = x+y+z | ||
+ | </code> | ||
+ | < | ||
+ | sumaYResta :: Int -> Int -> (Int,Int) | ||
+ | sumaYResta x y = (x+y, x-y) | ||
+ | </code> | ||
+ | Y los probamos desde el //prompt//. | ||
+ | |||
+ | < | ||
Main> suma3upla (2,3,4) | Main> suma3upla (2,3,4) | ||
9 | 9 | ||
Main> sumaYResta 2 3 | Main> sumaYResta 2 3 | ||
(5,-1) | (5,-1) | ||
+ | </ | ||
+ | |||
+ | Las tuplas pueden contener cualquier elemento de cualquier tipo, y se pueden mezclar tipos dentro de una misma tupla. Por ejemplo, podemos tener que el primer elemento de una tupla sea una cadena de caracteres y el segundo un número, el primero, una lista, el segundo elemento un booleano y el tercero otra lista, y así todas las combinaciones que se les ocurran. | ||
+ | |||
+ | ====Listas==== | ||
- | Haskell también maneja | + | Las listas |
+ | Las listas se escriben entre corchetes y se separan los elementos mediante comas. Pero esta forma de representar las listas es una forma abreviada de escribir lo que haskell interpreta internamente como una anidación de tuplas de profundidad indeterminada. De hecho '' | ||
- | ===== Ejemplo: la función bisiesto ===== | + | Dado que las listas son en realidad anidaciones de tuplas, podemos trabajar con su estructura como tuplas, y separar la parte inicial de la lista del resto, lo que se suele llamar //cabeza// y //cola//. Por ejemplo, en la siguiente función: |
+ | < | ||
+ | esVacia :: [a] -> Bool | ||
+ | esVacia [] = True | ||
+ | esVacia (x: | ||
+ | </ | ||
+ | |||
+ | Pero no sólo podemos distinguir el primer elemento de una lista, podemos distinguir //cualquier fracción inicial//. Cuando decimos que podemos distinguir cualquier fracción inicial de una lista, lo que queremos decir es que nos podemos referir al n-ésimo elemento de una lista, eso sí, para hacerlo tenemos que hacerlo con un patrón en el que se representen todos los elementos desde el primero hasta el n-1. Por ejemplo, si queremos referirnos al tercer elemento de una lista, tendremos que referirnos también al primero y al segundo, aunque sea mediante un patrón irrefutable, | ||
+ | < | ||
+ | tercero [a] -> a | ||
+ | tercero [_: | ||
+ | </ | ||
+ | |||
+ | Sin embargo, podemos dejar el resto de la lista sin detallar cuántos elementos hay. No podemos distinguir fracciones finales de las listas porque la estructura de tuplas requiere que para distinguir el //n+1// elemento de una tupla hayamos distinguido el elemento //n//. | ||
+ | |||
+ | Definimos un predicado que decide si //hay 2 o más elementos en una lista//: | ||
+ | < | ||
+ | alMenos2 :: [a] -> Bool | ||
+ | alMenos2 [] = False | ||
+ | alMenos2 [x] | ||
+ | alMenos2 (x:y:xs) = True | ||
+ | </ | ||
+ | |||
+ | =====Comparación de patrones===== | ||
+ | |||
+ | En haskell, como en prolog, las diferentes funciones se aplican por **unificación**. Es decir, cuando el intérprete trata de resolver algo, lo resuelve buscando alguna definición de función cuya parte izquierda pueda unificarse con lo que el intérprete está tratando de resolver. | ||
+ | |||
+ | Cómo hace el intérprete para llegar desde nuestra pregunta al resultado? En el siguiente ejemplo: | ||
+ | < | ||
+ | Main> alMenos2 [1, | ||
+ | True | ||
+ | </ | ||
+ | El intérprete busca alguna definición de función que pueda unificar con '' | ||
+ | < | ||
+ | alMenos2 [] = False | ||
+ | </ | ||
+ | Pero este caso no le sirve porque no puede unificar la lista vacía '' | ||
+ | |||
+ | Después encuentra otro caso en el que se define '' | ||
+ | < | ||
+ | alMenos2 [x] = False | ||
+ | </ | ||
+ | Finalmente, encuentra un caso de una lista con dos o más elementos, con la que sí puede unificar: | ||
+ | < | ||
+ | alMenos2 (x:y:xs) = True | ||
+ | </ | ||
+ | Vamos a prestar un poco más de atención al patrón que describe listas con uno o más elementos. En primer lugar vemos que se usan paréntesis. No es porque se trate de una tupla, sino para evitar errores de precedencia con el operador "'':''" | ||
+ | < | ||
+ | alMenos2 | ||
+ | ----------- | ||
+ | [a] -> Bool | ||
+ | | ||
+ | : [a] | ||
+ | | ||
+ | [a] | ||
+ | -------------------------- | ||
+ | | ||
+ | </ | ||
+ | Notemos que hemos usado la variable '' | ||
+ | |||
+ | A la unificación también se la llama correspondencia de patrones o //pattern matching//, y a los elementos que unifican se los puede llamar patrones. Así, los diferentes casos que especificamos al definir por casos una función se pueden llamar también " | ||
+ | |||
+ | ====El patrón irrefutable==== | ||
+ | |||
+ | Hemos visto que las variables se escriben con minúscula. Como en prolog, también tenemos una variable comodín, que puede unificar con cualquier cosa, y se escribe de la misma forma que en prolog, con el guión bajo " | ||
+ | |||
+ | Veamos algunos ejemplos de uso del patrón irrefutable. Recuerden que habíamos visto la función '' | ||
+ | < | ||
+ | esVacia :: [a] -> Bool | ||
+ | esVacia [] = True | ||
+ | esVacia (x:xs) = False | ||
+ | </ | ||
+ | Podemos usar comodines en ambas partes del segundo patrón o bien un patrón irrefutable y comodín a la vez. | ||
+ | < | ||
+ | esVacia' | ||
+ | esVacia' | ||
+ | esVacia' | ||
+ | |||
+ | esVacia'' | ||
+ | esVacia'' | ||
+ | esVacia'' | ||
+ | </ | ||
+ | |||
+ | También se puede aplicar a la función '' | ||
+ | < | ||
+ | alMenos2 :: [a] -> Bool | ||
+ | alMenos2 [] = False | ||
+ | alMenos2 [x] = False | ||
+ | alMenos2 (x:y:xs) = True | ||
+ | </ | ||
+ | Esta segunda versión es bastante más difícil de leer que la primera, por el uso y abuso del orden de evaluación de los patrones, patrones irrefutables y comodines. Los patrones irrefutables son muy útiles, pero no debemos dejar que nos impidan entender lo que escribimos ;). | ||
+ | < | ||
+ | alMenos2' | ||
+ | alMenos2' | ||
+ | alMenos2' | ||
+ | </ | ||
+ | |||
+ | Veamos ahora un ejemplo de **mal** uso del patrón irrefutable: | ||
+ | |||
+ | < | ||
+ | esCeroOUno :: Int -> Bool | ||
+ | esCeroOUno 0 = True | ||
+ | esCeroOUno _ = False | ||
+ | esCeroOUno 1 = True | ||
+ | </ | ||
+ | |||
+ | Si probamos | ||
+ | < | ||
+ | Main> esCeroOUno 1 | ||
+ | False | ||
+ | </ | ||
+ | |||
+ | Por qué nos devuelve falso? Porque en haskell, como en prolog, los patrones se aplican en el **orden** en el que se encuentran en el archivo de la base de conocimiento: | ||
+ | |||
+ | El programa que hace lo que nosotros esperamos tiene esto en cuenta y ordena los patrones de forma que se aplique el patrón irrefutable sólo cuando todo el resto falla. | ||
+ | |||
+ | < | ||
+ | esCeroOUno :: Int -> Bool | ||
+ | esCeroOUno 0 = True | ||
+ | esCeroOUno 1 = True | ||
+ | esCeroOUno _ = False | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Un ejemplo: la función bisiesto ===== | ||
A manera de ejemplo veamos el ejercicio 8.7 del apunte, donde tenemos que definir una función muy útil para cualquier aparato que maneje un calendario (relojes, celulares, PDAs, computadoras, | A manera de ejemplo veamos el ejercicio 8.7 del apunte, donde tenemos que definir una función muy útil para cualquier aparato que maneje un calendario (relojes, celulares, PDAs, computadoras, | ||
Línea 211: | Línea 399: | ||
Una definición matemática concisa sería //bisiesto n = 4|n /\ (100|n => 400|n)//. | Una definición matemática concisa sería //bisiesto n = 4|n /\ (100|n => 400|n)//. | ||
- | Entonces podemos seguir agregando definiciones de funciones a nuestro archivo '' | ||
Veamos tres versiones distintas ((Esto es una mala copia de [[http:// | Veamos tres versiones distintas ((Esto es una mala copia de [[http:// | ||
- | **La del viejo programadora/ | + | **La del programadora/ |
bisiesto'' | bisiesto'' | ||
Línea 228: | Línea 415: | ||
| n `mod` 4 == 0 = n `mod` 100 /= 0 || n `mod` 400 == 0 | | n `mod` 4 == 0 = n `mod` 100 /= 0 || n `mod` 400 == 0 | ||
- | **El que cursó [[http:// | + | **El que entiende mucho de programación declarativa |
bisiesto :: Int -> Bool | bisiesto :: Int -> Bool | ||
bisiesto n = n `mod` 4 == 0 && (n `mod` 100 /= 0 || n `mod` 400 == 0) | bisiesto n = n `mod` 4 == 0 && (n `mod` 100 /= 0 || n `mod` 400 == 0) | ||
- | |||
- | Podemos poner las tres versiones en nuestro script y probarlas rápidamente usando la función '' | ||
- | |||
- | Main> filter bisiesto [1945..2006] | ||
- | [1948, | ||
- | Main> filter bisiesto' | ||
- | [1948, | ||
- | Main> filter bisiesto'' | ||
- | [1948, | ||
- | |||
- | Vemos que las tres funciones operan correctamente en el rango de números dados ((No queremos decir que sean correctas en su totalidad, solo decimos que en ese rango no tienen fallas)). | ||
- | |||
- | |||
- | |||
- | |||
- | |||
===== Ejercicios ===== | ===== Ejercicios ===== | ||
- | Para realizar | + | Hay muchos ejercicios para hacer, no se preocupen si no pueden terminarlos todos!! Vamos a ver algunos de ellos en la próxima |
- | + | ||
- | * Definir la función //sumaRat (a,b) (c,d)//, //sumaRat : (Int,Int) -> (Int,Int) -> (Int, | + | |
- | + | ||
- | No es necesario realizar ninguna simplificación al resultado. | + | |
- | + | ||
- | probar con (1,2) y (1,2), (1,4) y (1,4). | + | |
- | * Definir una función //ordena.(x,y)//, //ordena : (Int,Int) -> (Int,Int)// que, dados dos enteros, los ordena de menor a mayor. | + | * Definir una función //ordena (x,y)//, // |
probar con (0,1), (2,2), (3,1). | probar con (0,1), (2,2), (3,1). | ||
- | * Definir una función // | + | * Definir una función // |
probar con 5 y 9, con -8 y 9, con -10 y -1, con 0 y 0 y con 0 y 3 | probar con 5 y 9, con -8 y 9, con -10 y -1, con 0 y 0 y con 0 y 3 | ||
* Ejercicio 8.7 del Apunte\\ | * Ejercicio 8.7 del Apunte\\ | ||
- | Definir la función //edad : (Int, Int, Int) -> (Int, Int, Int) -> Int// que dadas dos fechas indica los años transcurridos entre ellas. Por ejemplo edad.(20, | + | Definir la función // |
Suponer que las fechas están siempre bien formadas y que la primera es menor o igual a la segunda. | Suponer que las fechas están siempre bien formadas y que la primera es menor o igual a la segunda. | ||
Línea 279: | Línea 443: | ||
En un prisma rectangular, | En un prisma rectangular, | ||
la siguiente definición del área del prisma: \\ | la siguiente definición del área del prisma: \\ | ||
- | //area.h.b.d = 2 ∗ frente + 2 ∗ lado + 2 ∗ arriba// \\ | + | //area h b d = 2 ∗ frente + 2 ∗ lado + 2 ∗ arriba// \\ |
//|[ | //|[ | ||
donde //frente//, //lado// y //arriba// son las caras frontal, lateral y superior del prisma respectivamente.\\ | donde //frente//, //lado// y //arriba// son las caras frontal, lateral y superior del prisma respectivamente.\\ | ||
- | Completar la función //area.h.b.d// //area : Int -> Int -> Int -> Int// que calcula el área de un prisma rectangular: | + | Completar la función //area h b d// // |
area :: Int -> Int -> Int -> Int | area :: Int -> Int -> Int -> Int | ||
- | area.h.b.d = 2*frente + 2*lado + 2*tapa | + | area h b d = 2*frente + 2*lado + 2*tapa |
where | where | ||
frente = ... | frente = ... | ||
lado = ... | lado = ... | ||
tapa = ... | tapa = ... | ||
+ | |||
+ | * Programar en haskell una [[http:// | ||
+ | |||
+ | * Definir la función //cabeza xs//, //cabeza :: [a] --> a//, que devuelve el primer elemento de una lista. | ||
+ | |||
+ | probar con [1,2,3], con [3,3,3] y con []. | ||
+ | |||
+ | * Definir la función //cola xs//, //cola :: [a] --> [a]//, que devuelve toda la lista menos el primer elemento. | ||
+ | |||
+ | probar con [1,2,3], con [3,3,3] y con []. | ||
+ | |||
+ | * Definir una función // | ||
+ | |||
+ | probar con [1,2,3], con [3,3,3], con [0], con [0,1] y con []. | ||
+ | |||
+ | * Definir una función // | ||
+ | |||
+ | probar con (1,2) y [3,2,4,5], (0,0) y [], (1,2) y [2,3,4,5]. | ||
+ | |||
+ | * Definir una función // | ||
+ | Ayuda: fíjense que el resultado siempre debe ser una lista de caracteres! | ||
+ | |||
+ | probar con [' | ||
+ | |||
+ | * Definir una función // |
introalg/taller09_3.1239415892.txt.gz · Última modificación: 2018/08/10 03:03 (editor externo)