introalg:taller09_3
Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
introalg:taller09_3 [2009/04/13 12:35] – laura | introalg:taller09_3 [2018/08/10 03:03] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 24: | Línea 24: | ||
</ | </ | ||
- | 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:// |
< | < | ||
Línea 44: | Línea 44: | ||
[laura@azul Taller]$ | [laura@azul Taller]$ | ||
</ | </ | ||
- | Así volvemos al modo normal de la computadora. | ||
=====Incorporando conocimiento===== | =====Incorporando conocimiento===== | ||
- | 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 de las que se encuentran en el [[http:// |
- | + | ||
- | Como ejemplo, vamos a ver todo el proceso de **creación del programa - carga en memoria - prueba - modificación del programa - recarga**, con el Ejercicio 8.3 del apunte [[http:// | + | |
- | + | ||
- | 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. | + | |
+ | Como ejemplo, vamos a ver todo el proceso de **creación del programa - carga en memoria - prueba - modificación del programa - recarga**, con el Ejercicio 8.3 del apunte [[http:// | ||
+ | < | ||
+ | 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...) o, si no, se puede invocar el comando para editar un (nuevo) archivo '': | Para crear un programa se puede hacer mediante un editor de texto cualquiera (kate, bloc de notas, emacs...) o, si no, se puede invocar el comando para editar un (nuevo) archivo '': | ||
< | < | ||
- | | + | Hugs.Base> |
</ | </ | ||
- | Una posible | + | Se nos ocurre la siguiente |
< | < | ||
sgn :: Int -> Int | sgn :: Int -> Int | ||
Línea 72: | Línea 71: | ||
ERROR " | ERROR " | ||
</ | </ | ||
- | Pero el intérprete indica un error! Por qué? En la última línea del programa, vemos que usamos el mismo símbolo " | + | Pero el intérprete indica un error! Por qué? En la última línea del programa, vemos que usamos el mismo símbolo " |
Las traducciones de los símbolos son más o menos directas, de todas formas preparamos una tabla de [[http:// | Las traducciones de los símbolos son más o menos directas, de todas formas preparamos una tabla de [[http:// | ||
Línea 106: | Línea 105: | ||
1 | 1 | ||
</ | </ | ||
- | El número es demasiado grande y el intérprete se queda sin capacidad para tratarlo. | + | El número es demasiado grande y el intérprete se queda sin capacidad para tratarlo, si le damos un número más chico, sí funciona. |
< | < | ||
Main> sgn (-1 | Main> sgn (-1 | ||
Línea 150: | Línea 149: | ||
| x==0 = 0 | | 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 ('' | + | 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 ('' |
Por lo tanto, lo que hay a la izquierda del símbolo " | Por lo tanto, lo que hay a la izquierda del símbolo " | ||
Línea 165: | Línea 164: | ||
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. | 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. | ||
- | Vemos que al definir '' | + | Vemos que al definir '' |
Vamos a ver que en haskell hay varias formas de expresar estas condiciones para que se cumpla una determinada forma de calcular un resultado, en el apartado sobre [[# | Vamos a ver que en haskell hay varias formas de expresar estas condiciones para que se cumpla una determinada forma de calcular un resultado, en el apartado sobre [[# | ||
Línea 172: | Línea 171: | ||
===== Tipos de datos===== | ===== Tipos de datos===== | ||
- | Haskell es un lenguaje tipado, es decir, | + | Haskell es un lenguaje tipado, es decir, |
< | < | ||
- | | + | sgn :: Int -> Int -- esta línea es la signatura de tipos de la función sgn |
- | sgn x | 0< | + | sgn x | 0< |
- | | x< | + | | x< |
- | | x==0 = 0 | + | | x==0 = 0 |
</ | </ | ||
La signatura de tipos está formada por el nombre de la función y el tipo de sus parámetros y resultado. El nombre va seguido de ''::'' | La signatura de tipos está formada por el nombre de la función y el tipo de sus parámetros y resultado. El nombre va seguido de ''::'' | ||
< | < | ||
- | | + | sgn :: Int -> Int |
- | reverse :: [a] -> [a] | + | reverse :: [a] -> [a] |
- | map :: (a -> b) -> [a] -> [b] | + | map :: (a -> b) -> [a] -> [b] |
</ | </ | ||
Pequeño ejercicio sobre la aridad((Recuerden que la aridad es el número de argumentos de la función: unaria si tiene un argumento, binaria si tiene dos, etc.)) de las funciones: cuál de estas tres funciones es unaria, cuál binaria, cuál ternaria? | Pequeño ejercicio sobre la aridad((Recuerden que la aridad es el número de argumentos de la función: unaria si tiene un argumento, binaria si tiene dos, etc.)) de las funciones: cuál de estas tres funciones es unaria, cuál binaria, cuál ternaria? | ||
Línea 239: | Línea 238: | ||
Veamos algunos ejemplos: | Veamos algunos ejemplos: | ||
< | < | ||
- | | + | suma3upla :: (Int, |
- | suma3upla (x,y,z) = x+y+z | + | suma3upla (x,y,z) = x+y+z |
- | + | </ | |
- | sumaYResta :: Int -> Int -> (Int,Int) | + | < |
- | sumaYResta x y = (x+y, x-y) | + | sumaYResta :: Int -> Int -> (Int,Int) |
+ | sumaYResta x y = (x+y, x-y) | ||
</ | </ | ||
Línea 269: | Línea 269: | ||
esVacia (x:xs) = False | esVacia (x:xs) = False | ||
</ | </ | ||
- | Por cierto que 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'' | + | 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, |
- | esVacia'' | + | < |
- | esVacia'' | + | tercero |
+ | tercero | ||
</ | </ | ||
- | Pero no sólo podemos | + | Sin embargo, |
- | + | ||
- | Definimos un predicado que decide si //hay 2 o más elementos en una lista// y damos dos versiones una bastante legible y la otra ultracompacta y un tanto más críptica que hace uso y abuso del orden de evaluación de los patrones, patrones irrefutables y comodines. | + | |
+ | Definimos un predicado que decide si //hay 2 o más elementos en una lista//: | ||
< | < | ||
alMenos2 :: [a] -> Bool | alMenos2 :: [a] -> Bool | ||
Línea 289: | Línea 284: | ||
alMenos2 [x] = False | alMenos2 [x] = False | ||
alMenos2 (x:y:xs) = True | alMenos2 (x:y:xs) = True | ||
- | |||
- | alMenos2' | ||
- | alMenos2' | ||
- | alMenos2' | ||
</ | </ | ||
Línea 299: | Línea 290: | ||
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. | 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. | ||
- | ****ejemplos | + | 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 | ||
+ | < | ||
+ | alMenos2 [] = False | ||
+ | </ | ||
+ | Pero este caso no le sirve porque no puede unificar la lista vacía '' | ||
- | Si unifica, | + | Después encuentra otro caso en el que se define '' |
- | + | < | |
- | *** ejemplo*** | + | 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 " | 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 " | ||
Línea 309: | Línea 327: | ||
====El patrón irrefutable==== | ====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 " | + | 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 | ||
+ | < | ||
+ | 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** | ||
< | < | ||
Línea 372: | Línea 423: | ||
===== Ejercicios ===== | ===== Ejercicios ===== | ||
+ | Hay muchos ejercicios para hacer, no se preocupen si no pueden terminarlos todos!! Vamos a ver algunos de ellos en la próxima clase para consolidar los conceptos que hemos visto en esta. | ||
- | * 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 391: | 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 = ... | ||
Línea 406: | Línea 458: | ||
* Programar en haskell una [[http:// | * 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.1239626129.txt.gz · Última modificación: 2018/08/10 03:03 (editor externo)