Tabla de Contenidos
Clase 1
Plan para hoy
- Introducción al uso de Hugs
- Cómo escribir programas Haskell
- Escribiendo los primeros programas
Clase
Hugs es un intérprete del lenguaje funcional puro Haskell.
Durante este taller escribiremos, probaremos y utilizaremos los programas funcionales que se dan en el teórico.
A Hugs se lo invoca desde la línea de comandos o picando sobre el ícono 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 o comandos.
[nicolasw@azul Taller]$ hugs __ __ __ __ ____ ___ _________________________________________ || || || || || || ||__ Hugs 98: Based on the Haskell 98 standard ||___|| ||__|| ||__|| __|| Copyright (c) 1994-2005 ||---|| ___|| World Wide Web: http://haskell.org/hugs || || Report bugs to: hugs-bugs@haskell.org || || Version: March 2005 _________________________________________ Haskell 98 mode: Restart with command line option -98 to enable extensions Type :? for help Hugs.Base>
De este modo Hugs se convierte en una calculadora, esperando que se introduzca una expresión para evaluarla e imprimir el resultado, y luego volver a pedir una expresión (lazo leer-evaluar-imprimir).
Gracias al preludio standard tenemos muchas funciones ya definidas.
Hugs.Base> 21+21 42 Hugs.Base> 2*4 == 10 `div` 5 && True False Hugs.Base> [2,3,5,7,11]++[1,2] [2,3,5,7,11,1,2] Hugs.Base> reverse "dabale arroz a la zorra el abad" "daba le arroz al a zorra elabad"
Este ciclo continúa indefinidamente hasta que pidamos la salida del intérprete con CTRL-D o con el comando
Hugs.Base> :q [Leaving Hugs] [nicolasw@azul Taller]$
Para poder dar nuevas definiciones y/o funciones necesitamos escribir un programa funcional o script Haskell.
Un programa funcional es un archivo con terminación .hs donde se escriben en texto plano todas las definiciones que conforman el programa funcional.
A manera de ejemplo realicemos un ciclo de creación-carga-prueba-modificación-recarga, con el Ejercicio 8.3 del apunte Extracto del Cálculo de Programas.
Para crear un script basta con invocar el comando para editar un (nuevo) archivo :e ejercicios8.hs
.
Una posible solución para el problema de la función signo es la siguiente:
sgn :: Int -> Int sgn x | 0<x = 1 | x<0 = -1 | x=0 = 0
Luego de salvar el programa y cargarlo, el intérprete indica un error pues =
es el símbolo de definición, mientras que la comparación es ==
.
Hugs.Base> :e ejercicios8.hs Hugs.Base> :l ejercicios8.hs ERROR "ejercicios8.hs":4 - Syntax error in input (unexpected `=')
Las traducciones son más o menos directas, de todas formas preparamos una tabla de Traducción de Cálculo de Programas a Haskell.
Volvemos a editar el script con :e
(el nombre ya no lo necesitamos ya que tenemos cargado este script) y corregimos x=0
por x==0
.
Podemos probar la nueva función para ganar confianza en su corrección.
Main> sgn 1 1 Main> sgn 0 0 Main> sgn -1 ERROR - Cannot infer instance *** Instance : Num (Int -> Int) *** Expression : sgn - 1 Main> sgn (-1) -1 Main> sgn 123123123123 Program error: arithmetic overflow Main> sgn 123123123 1 Main> sgn 1.1 ERROR - Cannot infer instance *** Instance : Fractional Int *** Expression : sgn 1.1 Main> sgn (-1 ERROR - Syntax error in expression (unexpected end of input) Main> map sgn [-10..10] [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,1,1,1,1,1,1,1,1,1]
Notamos los distintos tipos de errores que se producen por problemas de
- Precedencia
- Tipos
- Sintáxis
A manera de ejemplo veamos el ejercicio 8.7, donde tenemos que definir una función muy útil para cualquier aparato que maneje un calendario (relojes, celulares, PDAs, computadoras, DVD-R, etc.). La signatura 1) es bisiesto: Int → Bool, y es un predicado que devuelve true si el año es bisiesto y false en caso contrario. Recordemos cuando un año es bisiesto:
La regla completa para los años bisiestos según el calendario Gregoriano es: Un año es bisiesto si es divisible por 4, excepto aquellos divisibles por 100 pero no por 400.
Entonces podemos seguir agregando definiciones de funciones a nuestro archivo ejercicios8.hs
con el comando :e
.
Veamos tres versiones distintas 2).
La del viejo programadora/or
bisiesto'' :: Int -> Bool bisiesto'' n = if n `mod` 4 /= 0 then False else if n `mod` 100 /= 0 then True else if n `mod` 400 == 0 then True else False
El que está aprendiendo Haskell
bisiesto' :: Int -> Bool bisiesto' n | n `mod` 4 /= 0 = False | n `mod` 4 == 0 = n `mod` 100 /= 0 || n `mod` 400 == 0
El que cursó Introducción a los Algoritmos
bisiesto :: Int -> Bool 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 filter
para que obtener solo los años bisiestos desde 1945 al 2006.
Main> filter bisiesto [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004] Main> filter bisiesto' [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004] Main> filter bisiesto'' [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004]
Vemos que las tres funciones operan correctamente en el rango de números dados 3).
Ejercicios
Para realizar en lo que resta de la clase.
- Ejercicio 8.7
Definir la función edad : (Nat, Nat, Nat) → (Nat, Nat, Nat) → Int que dadas dos fechas indica los años transcurridos entre ellas. Por ejemplo edad.(20,10,1968).(30,4,1987) = 18
- Ejercicio 8.8
En un prisma rectangular, llamemos h a la altura, b al ancho y d a la profundidad. Completar
la siguiente definición del área del prisma:
area.h.b.d = 2 ∗ frente + 2 ∗ lado + 2 ∗ arriba
|[ …aca va la definicion… ]|
donde frente, lado y arriba son las caras frontal, lateral y superior del prisma respectivamente.